@use '~flux/components/css/mixin';

%-form-input-group-inner-styles {
    height: 100%;
    min-height: unset;
    border: 0;
    border-radius: 0;

    @include mixin.focus-ring-remove();

    &:first-child {
        border-top-left-radius: calc(var(--radius) - 1px);
        border-bottom-left-radius: calc(var(--radius) - 1px);
    }

    &:last-child {
        border-top-right-radius: calc(var(--radius) - 1px);
        border-bottom-right-radius: calc(var(--radius) - 1px);
    }
}

.formStructureElement {
    display: flex;
    flex-flow: column;
}

.form {
    composes: formStructureElement;

    counter-reset: flux-step;
    gap: 42px;
}

:local(.pane) > .form {
    display: contents;
    gap: 0;
}

.formColumn,
.formSection {
    composes: formStructureElement;

    gap: 18px;
}

.form,
.formColumn,
.formSection {
    > .button {
        align-self: flex-start;
    }
}

.formGrid {
    --columns: 2;

    display: grid;
    gap: 18px;
    grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
}

.formRow {
    display: flex;
    flex-grow: 1;
    gap: 18px;
}

.formSectionTitle {
    @include mixin.text(xlarge);

    color: var(--foreground-prominent);
    font-weight: 800;
}

.formStep {
    composes: formStructureElement;

    counter-increment: flux-step;
    gap: 12px;
}

.formStepHeader {
    display: flex;
    align-items: flex-start;
    gap: 12px;
}

.formStepNumber {
    @include mixin.text(xsmall);

    display: inline-flex;
    height: 27px;
    width: 27px;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    background: var(--primary-50);
    border-radius: var(--radius);
    color: var(--primary-600);
    font-weight: 700;
    font-variant-numeric: tabular-nums;

    &::before {
        content: counter(flux-step);
    }
}

.formStepHeading {
    display: flex;
    min-width: 0;
    flex-flow: column;
    gap: 3px;
}

.formStepTitle {
    // Matches the 27px .formStepNumber circle it sits next to.
    @include mixin.text(large, $line-height: 27px);

    color: var(--foreground-prominent);
    font-weight: 700;
}

.formStepSubtitle {
    color: var(--foreground-secondary);
}

.formStepEnd {
    display: inline-flex;
    margin-left: auto;
    align-items: center;
}

.formStepContent {
    display: flex;
    margin-left: 39px;
    flex-flow: column;
    gap: 12px;
}

@include mixin.breakpoint-down(sm) {
    .formGrid {
        grid-template-columns: 1fr;
    }

    .formRow {
        flex-flow: column;
        gap: 18px;
    }
}

.formField {
    display: flex;
    flex: 1 1 0;
    flex-flow: column;
    gap: 6px;
}

.formFieldHeader {
    display: flex;
    width: 100%;
    margin-bottom: 0;
    align-items: center;
    align-self: flex-start;
    gap: 6px;
}

.formFieldLabel {
    // Reserves one line even when the label wraps to nothing, so fields with and
    // without a label keep the same header height.
    min-height: var(--line-height-default);
    color: var(--foreground-prominent);
    font-weight: 600;
}

.formFieldOptional {
    @include mixin.text(xsmall);

    color: var(--foreground-secondary);
}

.formFieldValue {
    @include mixin.text(xsmall);

    margin-left: auto;
    color: var(--foreground-secondary);
}

.formFieldCounter {
    @include mixin.text(xsmall);

    margin-left: auto;
    color: var(--foreground-secondary);
    white-space: nowrap;
}

.formFieldAddition {
    @include mixin.text(small);

    display: flex;
    margin-top: 3px;
    margin-bottom: 3px;
    gap: 9px;
}

.formFieldAdditionIcon {
    // Centres the 16px icon on the first line box.
    margin-top: calc((var(--line-height-small) - 16px) / 2);
}

.formFieldAdditionError {
    composes: formFieldAddition;

    color: var(--danger-600);
}

.formFieldAdditionHint {
    composes: formFieldAddition;

    color: var(--foreground-secondary);
}

.formFieldAddition + .formFieldAddition {
    margin-top: 0;
}

.formInput {
    // An input owns its text: its height is fixed, so the value must not follow
    // the font-size of whatever it happens to sit in. The native input inherits
    // this pair through its own font: inherit.
    @include mixin.text(default);

    position: relative;
    display: block;
    height: 42px;
    width: 100%;
    padding: 0 12px;
    background: var(--surface);
    background-clip: padding-box;
    border: 1px solid var(--surface-stroke);
    border-radius: var(--radius);
    box-shadow: var(--shadow-px);
    color: var(--foreground);
    outline: 0 solid transparent;
    transition: var(--transition-default);
    transition-property: background, border-color, mixin.focus-ring-transition-properties();

    &::placeholder {
        color: var(--foreground-secondary);
    }

    &.isSecondary {
        background: var(--gray-100);
        border-color: transparent;
        box-shadow: none;
    }

    &.isCondensed {
        height: 34px;
    }

    &.isInvalid {
        border-color: var(--danger-500);
    }
}

.form .formInput {
    align-self: start;
}

.formInputDisabled {
    composes: formInput;

    background: var(--surface-disabled);
    color: var(--foreground-secondary);
    cursor: not-allowed;

    input {
        cursor: inherit;
    }
}

.formInputEnabled {
    composes: formInput;

    @include mixin.focus-ring(-1px, true);

    @include mixin.hover {
        border-color: var(--surface-stroke-hover);
    }
}

.formInputIcon {
    position: absolute;
    margin-top: 11px;
    margin-bottom: 11px;
    color: var(--foreground-secondary);
    pointer-events: none;
}

.formInputIconTrailing {
    composes: formInputIcon;

    right: 12px;
}

.formInputIconLeading {
    composes: formInputIcon;

    left: 12px;
}

.formInputIconPasswordToggle {
    composes: formInputIconTrailing;

    display: inline-flex;
    padding: 0;
    align-items: center;
    justify-content: center;
    background: unset;
    border: 0;
    color: var(--foreground-secondary);
    pointer-events: unset;
    cursor: pointer;

    @include mixin.hover {
        color: var(--foreground);
    }

    &:disabled {
        cursor: not-allowed;
        opacity: .5;
    }
}

.formInputNative {
    position: absolute;
    inset: 0;
    height: 100%;
    width: 100%;
    padding: 0 12px;
    background: unset;
    border: 0;
    border-radius: inherit;
    color: inherit;
    font: inherit;
    outline: 0;
    text-align: left;

    &::placeholder {
        color: var(--foreground-secondary);
    }

    &::-webkit-search-decoration,
    &::-webkit-search-cancel-button,
    &::-webkit-search-results-button,
    &::-webkit-search-results-decoration {
        -webkit-appearance: none;
    }

    &::-webkit-color-swatch {
        border: 0;
        border-radius: var(--radius-half);
    }

    &::-webkit-color-swatch-wrapper {
        width: calc(100% + 24px);
        margin: 0 -12px;
        padding: 3px;
    }
}

.formInputNativeHasIconLeading {
    padding-left: 42px;
}

.formInputNativeHasIconTrailing {
    padding-right: 42px;
}

.formNumberInputNative {
    composes: formInputNative;

    padding-right: 38px;
    appearance: textfield;
    -moz-appearance: textfield;
    font-variant-numeric: tabular-nums;

    &::-webkit-outer-spin-button,
    &::-webkit-inner-spin-button {
        margin: 0;
        -webkit-appearance: none;
    }
}

.formNumberInputButtons {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    display: flex;
    flex-direction: column;
    width: 33px;
    border-left: 1px solid var(--surface-stroke);
    border-radius: 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0;
    overflow: hidden;
}

.formNumberInputButton {
    display: flex;
    flex: 1 1 0;
    margin: 0;
    padding: 0;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    border: 0;
    color: var(--foreground-secondary);
    cursor: pointer;
    transition: var(--transition-default);
    transition-property: background, color;

    & + & {
        border-top: 1px solid var(--surface-stroke);
    }

    @include mixin.hover {
        background: var(--surface-hover);
        color: var(--foreground);
    }

    &:disabled {
        color: var(--surface-stroke);
        cursor: not-allowed;
    }
}

.formInputAddition {
    composes: formInput;

    display: flex;
    width: unset;
    align-items: center;
    flex-grow: 0;
    justify-content: center;
    background: var(--surface-disabled);
    color: var(--foreground-secondary);
    pointer-events: none;

    &:has(+ .formInput .formInputNative) {
        border-right: 1px solid var(--surface-stroke);
    }

    + .formInputAddition {
        border-left: 1px solid var(--surface-stroke);
    }

    @at-root .formInput:has(.formInputNative) + & {
        border-left: 1px solid var(--surface-stroke);
    }
}

.formInputGroup {
    composes: formInputEnabled;

    display: flex;
    padding: 0;

    @include mixin.focus-ring(-1px, true);

    > :is(.formInput, .formSelect, .button) {
        @extend %-form-input-group-inner-styles;

        + :is(.button, .buttonGroup) {
            margin: 0;
            border-left: 1px solid var(--surface-stroke);
        }
    }

    > .buttonGroup > .button {
        @extend %-form-input-group-inner-styles;

        + .button {
            margin: 0;
            border-left: 1px solid var(--surface-stroke);
        }
    }

    > .buttonGroup:not(:first-child) > .button:first-child {
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }

    &.isCondensed,
    &.isSecondary {
        .formInputAddition:not(:last-child) {
            padding-right: 0;
            background: unset;
            border-color: transparent;
        }
    }

    &.isSecondary {
        .formInput {
            background: transparent;
            border-color: transparent;
            box-shadow: none;
        }

        .secondaryButton {
            background: transparent;
            border-color: var(--surface-stroke);
            box-shadow: none;

            @include mixin.hover {
                background: var(--surface-stroke-hover);
            }
        }
    }

    &:has(*:disabled) {
        cursor: not-allowed;

        > * {
            pointer-events: none;
        }
    }

    :is(.button[disabled]),
    :is(.button[aria-disabled="true"]) {
        background: var(--surface-disabled);
        opacity: 1;

        &,
        .buttonIcon {
            color: var(--foreground-secondary);
        }
    }
}

.formDateInput {
    cursor: default;

    :is(input) {
        text-align: left;

        &::-webkit-input-placeholder {
            visibility: hidden;
        }

        &::-webkit-calendar-picker-indicator {
            display: none;
            -webkit-appearance: none;
        }
    }
}

.formDateRangeInput {
    composes: formInput;

    display: flex;
    align-items: center;
    cursor: default;
}

.formDateTimeInput {
    .formInput:last-child {
        max-width: 99px;
    }

    .inputGroup {
        flex-grow: 1;
    }
}

.formTimeInput {
    composes: formDateInput;
}

.formSelect {
    composes: formInput;

    position: relative;
    display: flex;
    height: unset;
    min-height: 42px;
    padding: 0 39px 0 6px;
    align-items: center;
    flex-wrap: wrap;
    gap: 0 6px;
    cursor: pointer;

    &:not(.isDisabled) {
        @include mixin.focus-ring(-1px, true);

        @include mixin.hover {
            border-color: var(--surface-stroke-hover);
        }
    }

    &.isDisabled {
        cursor: not-allowed;
    }

    &.isFocused {
        @include mixin.focus-outline-visible(-1px);
    }

    .badge {
        margin-top: 6px;
        margin-bottom: 6px;
        max-width: 100%;
        flex: 0 0 auto;
    }
}

.formSelectIcon {
    position: absolute;
    top: 50%;
    right: 12px;
    color: var(--foreground-secondary);
    translate: 0 -50%;
}

.formSelectInput {
    position: sticky;
    top: 0;
    height: 48px;
    margin-bottom: 9px;
    background: var(--surface);
    border-top: 0;
    border-left: 0;
    border-right: 0;
    border-radius: 0;
    outline: 0;
    z-index: 2;

    @include mixin.focus-ring-remove;

    .formInputIcon {
        right: 0;
        margin: 15px;
        font-size: 18px;
    }

    .formInputNative {
        padding-left: 18px;
        padding-right: 18px;
    }
}

.formSelectPlaceholder {
    margin-left: 6px;
    margin-right: 6px;
    color: var(--foreground-secondary);
    user-select: none;
}

.formSelectPopup {
    composes: basePane from './base/Pane.module.scss';

    position: fixed;
    display: block;
    top: 0;
    left: 0;
    width: var(--width, auto);
    max-height: max(330px, 50dvh);
    min-width: 120px;
    box-shadow: var(--shadow-md);
    overflow: auto;
    translate: var(--x) var(--y);
    z-index: 10000;

    .menuItem {
        contain-intrinsic-size: auto 42px;
        content-visibility: auto;
    }

    &.isKeyboardAction .menuItem {
        transition: 0s;
    }

    &.isSearchable .menuSubHeader {
        top: 48px;
    }
}

.formSelectSelected {
    position: absolute;
    height: 100%;
    padding-left: 12px;
    padding-right: 42px;
    inset: -1px;
    pointer-events: none;

    .buttonLabel {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

.formSelect.isDisabled .formSelectIcon {
    opacity: .5;
}

.formSelect.isDisabled .formSelectSelected {
    background: var(--surface-disabled);
    border: 1px solid var(--surface-stroke);
    color: var(--foreground-secondary);
    opacity: 1;
}

.formTextArea {
    height: unset;
    // 18px = padding / 2px = border
    min-height: calc(18px + 2px + var(--rows, 1) * 1lh);
    padding-top: 9px;
    padding-bottom: 9px;
    flex-shrink: 0;
    field-sizing: content;
    resize: vertical;
}

.formTextAreaDisabled {
    composes: formInputDisabled;
    composes: formTextArea;
}

.formTextAreaEnabled {
    composes: formInputEnabled;
    composes: formTextArea;
}

.formCheckboxGroup {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;

    &.isInline {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 8px 20px;
    }

    // Tiles stretch to the full width on their own. When laid out inline, let them
    // share the row in equal columns. Plain checkboxes mixed in keep their natural size.
    &.isInline:has(> .formCheckboxTile) {
        align-items: stretch;
        flex-wrap: nowrap;
        gap: 9px;

        > .formCheckboxTile {
            flex: 1 1 0;
            min-width: 0;
        }
    }

    // Connected tiles form a single block: shared borders, rounded outer corners only.
    &.isConnected {
        align-items: stretch;
        gap: 0;

        > .formCheckboxTile {
            position: relative;
            border-radius: 0;

            &:not(:first-child) {
                margin-top: -1px;
            }

            &:first-child {
                border-top-left-radius: var(--radius);
                border-top-right-radius: var(--radius);
            }

            &:last-child {
                border-bottom-left-radius: var(--radius);
                border-bottom-right-radius: var(--radius);
            }

            @include mixin.hover {
                z-index: 1;
            }

            &:has(.formCheckboxNative:is(:checked, :indeterminate)),
            &:has(.formCheckboxNative:focus-visible) {
                z-index: 1;
            }
        }

        &.isInline {
            flex-direction: row;
            flex-wrap: nowrap;
            gap: 0;

            > .formCheckboxTile {
                flex: 1 1 0;
                min-width: 0;

                &:not(:first-child) {
                    margin-top: 0;
                    margin-left: -1px;
                }

                &:first-child {
                    border-radius: var(--radius) 0 0 var(--radius);
                }

                &:last-child {
                    border-radius: 0 var(--radius) var(--radius) 0;
                }
            }
        }
    }
}

.formCheckbox {
    display: inline-flex;
    flex-shrink: 0;
    align-items: flex-start;
    gap: 12px;

    // The 20px box plus its 1px top margin is a 21px margin-box; the label's first
    // line box has to match it or the two stop lining up.
    line-height: 21px;
    outline: 0;

    &.isDisabled {
        cursor: not-allowed;

        .formCheckboxElement {
            background: var(--surface-disabled);
            border-color: var(--surface-stroke);
            color: var(--foreground-secondary);
        }

        .formCheckboxLabel {
            color: var(--foreground-secondary);
        }
    }

    &.isReadonly {
        cursor: default;

        .formCheckboxNative {
            pointer-events: none;
        }
    }

    &.isInvalid .formCheckboxElement {
        border-color: var(--danger-500);
    }
}

.formCheckboxElement,
.formCheckboxNative {
    margin: 1px 0 0;
    height: 20px;
    width: 20px;
}

.formCheckboxElement {
    position: relative;
    display: inline-flex;
    height: 20px;
    width: 20px;
    padding: 0;
    align-items: center;
    flex-shrink: 0;
    justify-content: center;
    background: var(--gray-50);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-half);
    color: var(--primary-25);
    cursor: pointer;
    pointer-events: none;
    transition: 210ms var(--swift-out);
    transition-property: background, border-color, color, mixin.focus-ring-transition-properties();

    @include mixin.focus-outline;

    .icon {
        opacity: 0;
        scale: .85;
        transition: inherit;
        transition-property: opacity;

        :is(path) {
            stroke: currentColor;
            stroke-width: 54px;
        }
    }
}

.formCheckboxText {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 3px;
}

.formCheckboxLabel {
    // Aligns with the 21px checkbox margin-box, not with the default 24px line.
    @include mixin.text(default, $line-height: 21px);
}

.formCheckboxSubLabel {
    @include mixin.text(small);

    color: var(--foreground-secondary);
}

.formCheckboxNative {
    position: absolute;
    cursor: pointer;
    opacity: 0;

    @include mixin.hover {
        + .formCheckboxElement {
            background: var(--gray-100);
        }
    }

    &:is(:checked, :indeterminate) + .formCheckboxElement {
        background: var(--primary-600);
        border-color: var(--primary-600);

        .icon {
            opacity: 1;
        }
    }

    &:focus-visible + .formCheckboxElement {
        @include mixin.focus-outline-visible(2px);
    }

    &:disabled {
        cursor: not-allowed;
    }

    &:disabled + .formCheckboxElement {
        background: var(--gray-100);
        border-color: var(--gray-200);
        color: var(--foreground-secondary);
    }
}

.formCheckboxTile {
    composes: formCheckbox;

    width: 100%;
    align-items: flex-start;
    padding: 15px 18px;
    background: var(--surface);
    border: 1px solid var(--surface-stroke);
    border-radius: var(--radius);
    color: var(--foreground);
    cursor: pointer;
    transition: 210ms var(--swift-out);
    transition-property: background, border-color, color, mixin.focus-ring-transition-properties();

    @include mixin.focus-outline;

    @include mixin.hover {
        background: var(--surface-hover);
    }

    &:has(.formCheckboxNative:focus-visible) {
        @include mixin.focus-outline-visible(2px);
    }

    &:has(.formCheckboxNative:is(:checked, :indeterminate)) {
        background: var(--primary-50);
        border-color: var(--primary-200);
        color: var(--primary-600);
    }

    &.isInvalid {
        border-color: var(--danger-500);
    }

    > .formCheckboxElement {
        order: 3;
    }

    > .formCheckboxIcon {
        order: 1;
        flex-shrink: 0;
        margin-top: 1px;
        color: var(--primary-600);
    }

    > .formCheckboxText {
        order: 2;
        flex: 1;
    }

    .formCheckboxLabel {
        font-weight: 500;
    }
}

.formRadioGroup {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;

    &.isInline {
        flex-direction: row;
        flex-wrap: wrap;
        gap: 9px 21px;
    }

    // Tiles stretch to the full width on their own. When laid out inline, let them
    // share the row in equal columns. Plain radios mixed in keep their natural size.
    &.isInline:has(> .formRadioTile) {
        align-items: stretch;
        flex-wrap: nowrap;
        gap: 9px;

        > .formRadioTile {
            flex: 1 1 0;
            min-width: 0;
        }
    }

    // Connected tiles form a single block: shared borders, rounded outer corners only.
    &.isConnected {
        align-items: stretch;
        gap: 0;

        > .formRadioTile {
            position: relative;
            border-radius: 0;

            &:not(:first-child) {
                margin-top: -1px;
            }

            &:first-child {
                border-top-left-radius: var(--radius);
                border-top-right-radius: var(--radius);
            }

            &:last-child {
                border-bottom-left-radius: var(--radius);
                border-bottom-right-radius: var(--radius);
            }

            @include mixin.hover {
                z-index: 1;
            }

            &:has(.formRadioNative:checked),
            &:has(.formRadioNative:focus-visible) {
                z-index: 1;
            }
        }

        &.isInline {
            flex-direction: row;
            flex-wrap: nowrap;
            gap: 0;

            > .formRadioTile {
                flex: 1 1 0;
                min-width: 0;

                &:not(:first-child) {
                    margin-top: 0;
                    margin-left: -1px;
                }

                &:first-child {
                    border-radius: var(--radius) 0 0 var(--radius);
                }

                &:last-child {
                    border-radius: 0 var(--radius) var(--radius) 0;
                }
            }
        }
    }
}

.formRadio {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
    align-items: flex-start;
    gap: 12px;

    // The 20px element plus its 1px top margin is a 21px margin-box; the label's
    // first line box has to match it or the two stop lining up.
    line-height: 21px;
    outline: 0;
    cursor: pointer;

    &.isDisabled {
        cursor: not-allowed;

        .formRadioElement {
            background: var(--surface-disabled);
            border-color: var(--surface-stroke);
        }

        .formRadioLabel {
            color: var(--foreground-secondary);
        }
    }

    &.isReadonly {
        cursor: default;

        .formRadioNative {
            pointer-events: none;
        }
    }

    &.isInvalid .formRadioElement {
        border-color: var(--danger-500);
    }
}

.formRadioElement,
.formRadioNative {
    margin: 1px 0 0;
    height: 20px;
    width: 20px;
}

.formRadioElement {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
    height: 20px;
    width: 20px;
    align-items: center;
    justify-content: center;
    background: var(--gray-50);
    border: 1px solid var(--gray-200);
    border-radius: 50%;
    cursor: pointer;
    pointer-events: none;
    transition: 210ms var(--swift-out);
    transition-property: background, border-color, mixin.focus-ring-transition-properties();

    @include mixin.focus-outline;

    &::after {
        content: '';
        height: 8px;
        width: 8px;
        background: var(--primary-25);
        border-radius: 50%;
        scale: 0;
        transition: inherit;
        transition-property: scale;
    }
}

.formRadioLabel {
    // Aligns with the 21px radio margin-box, not with the default 24px line.
    @include mixin.text(default, $line-height: 21px);
}

.formRadioNative {
    position: absolute;
    cursor: pointer;
    opacity: 0;

    @include mixin.hover {
        + .formRadioElement {
            background: var(--gray-100);
        }
    }

    &:checked + .formRadioElement {
        background: var(--primary-600);
        border-color: var(--primary-600);

        &::after {
            scale: 1;
        }
    }

    &:focus-visible + .formRadioElement {
        @include mixin.focus-outline-visible(2px);
    }

    &:disabled {
        cursor: not-allowed;
    }

    &:disabled + .formRadioElement {
        background: var(--gray-100);
        border-color: var(--gray-200);
    }
}

.formRadioText {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 3px;
}

.formRadioSubLabel {
    @include mixin.text(small);

    color: var(--foreground-secondary);
}

.formRadioTile {
    composes: formRadio;

    width: 100%;
    align-items: flex-start;
    padding: 15px 18px;
    background: var(--surface);
    border: 1px solid var(--surface-stroke);
    border-radius: var(--radius);
    color: var(--foreground);
    cursor: pointer;
    transition: 210ms var(--swift-out);
    transition-property: background, border-color, color, mixin.focus-ring-transition-properties();

    @include mixin.focus-outline;

    @include mixin.hover {
        background: var(--surface-hover);
    }

    &:has(.formRadioNative:focus-visible) {
        @include mixin.focus-outline-visible(2px);
    }

    &:has(.formRadioNative:checked) {
        background: var(--primary-50);
        border-color: var(--primary-200);
        color: var(--primary-600);
    }

    &.isInvalid {
        border-color: var(--danger-500);
    }

    > .formRadioElement {
        order: 3;
    }

    > .formRadioIcon {
        order: 1;
        flex-shrink: 0;
        margin-top: 1px;
        color: var(--primary-600);
    }

    > .formRadioText {
        order: 2;
        flex: 1;
    }

    .formRadioLabel {
        font-weight: 500;
    }
}

.formQuantitySelector {
    min-width: max-content;
    align-self: center;
    justify-self: center;
    border: 1px solid var(--surface-stroke);
    border-radius: var(--radius);
    box-shadow: var(--shadow-px);
    overflow: hidden;
    transition: var(--transition-default);
    transition-property: border-color, mixin.focus-ring-transition-properties();

    @include mixin.focus-ring(2px, true);

    @include mixin.hover {
        border-color: var(--surface-stroke-hover);
    }
}

.formQuantitySelectorButton {
    margin: -1px;
    border: 0;

    &:first-child {
        margin-right: 0;
    }

    &:last-child {
        margin-left: 0;
    }

    &,
    &:focus-visible,
    &:focus-within {
        outline: 0;
    }
}

.formQuantitySelectorInput {
    composes: formInput;

    margin: -1px 0;
    padding-left: 0;
    padding-right: 0;
    border-radius: 0;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    text-align: center;

    @include mixin.hover {
        border-color: var(--surface-stroke-hover);
    }

    &,
    &:focus-visible,
    &:focus-within {
        outline: 0 !important;
    }

    & {
        -moz-appearance: textfield;
    }

    &::-webkit-outer-spin-button,
    &::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
    }
}

.formPinInput {
    display: grid;
    width: min-content;
    gap: .4ch;
    grid-template-columns: repeat(var(--max-length, 0), 1fr);
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 24px;
    font-weight: 700;
}

.formPinInputField {
    padding: 0;
    width: 2.7ch;
    border: 1px solid var(--surface-stroke);
    border-radius: var(--radius);
    box-shadow: var(--shadow-px);
    font: inherit;
    line-height: 3.3ch;
    outline: 0;
    text-align: center;
    transition: var(--transition-default);
    transition-property: border-color, mixin.focus-ring-transition-properties();
}

.formPinInputEnabled {
    composes: formPinInput;

    .formPinInputField {
        background-color: var(--surface);
        color: var(--foreground-prominent);

        @include mixin.focus-ring(-1px, true);
    }
}

.formPinInputDisabled {
    composes: formPinInput;

    .formPinInputField {
        background-color: var(--surface-disabled);
        color: var(--foreground-secondary);
        cursor: not-allowed;
    }
}

.formToggle {
    position: relative;
    display: block;
    width: 54px;
    height: 30px;
    flex: 0 0 auto;
    background: var(--gray-50);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-full);
    contain: paint;

    @include mixin.focus-outline;

    &:has(.formToggleInput:focus-visible) {
        @include mixin.focus-outline-visible(2px);
    }

    &.isChecked {
        border-color: transparent;

        background: var(--primary-600);

        .formToggleInput::after {
            translate: 24px 0;
            border-color: transparent;
        }

        .formToggleIcon {
            color: var(--primary-25);
        }

        .formToggleIconOn {
            translate: calc(-50% + 24px) -50%;
        }
    }

    &:not(.isChecked) .formToggleIconOff {
        translate: calc(-50% - 24px) -50%;
    }

    &.isDisabled {
        cursor: not-allowed;
        opacity: .6;
    }

    &.isReadonly .formToggleInput {
        pointer-events: none;
    }

    &.isInvalid {
        border-color: var(--danger-500);
    }
}

.formToggleIcon {
    position: absolute;
    top: 50%;
    color: var(--foreground-secondary);
    pointer-events: none;
    translate: -50% -50%;
}

.formToggleIconOff {
    composes: formToggleIcon;

    left: 15px;
}

.formToggleIconOn {
    composes: formToggleIcon;

    left: 39px;
}

.formToggleInput {
    -webkit-appearance: none;
    appearance: none;

    position: relative;
    display: block;
    margin: 0;
    height: inherit;
    width: inherit;
    background: unset;
    border: 0;
    border-radius: inherit;
    cursor: pointer;
    outline: 0;

    &:disabled {
        cursor: not-allowed;
    }

    &::after {
        position: absolute;
        display: block;
        top: 2px;
        left: 2px;
        height: 24px;
        width: 24px;
        content: '';
        background: var(--surface);
        border: 1px solid var(--surface-stroke);
        border-radius: var(--radius-full);
        box-shadow: var(--shadow-sm);
    }
}

.formToggle,
.formToggleIcon,
.formToggleInput,
.formToggleInput::after {
    transition: 210ms var(--swift-out);
    transition-property: background, border-color, color, opacity, scale, translate, mixin.focus-ring-transition-properties();
}

.formTagsInput {
    composes: formInput;

    display: flex;
    height: unset;
    min-height: 42px;
    padding: 3px 6px;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    cursor: text;

    &:not(.formTagsInputDisabled) {
        @include mixin.focus-ring(-1px, true);
    }
}

.formTagsInputEnabled {
    composes: formTagsInput;
}

.formTagsInputDisabled {
    composes: formTagsInput;

    background: var(--gray-100);
    cursor: not-allowed;
}

.formTagsInputField {
    height: 30px;
    min-width: 60px;
    flex: 1 1 60px;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    outline: 0;

    // Align the placeholder with FluxFormInput (12px) when no tags precede the field.
    &:first-child {
        padding-left: 6px;
    }

    &::placeholder {
        color: var(--foreground-secondary);
    }

    &:disabled {
        cursor: not-allowed;
    }
}

.formTagsInputPopup {
    composes: formSelectPopup;
}
