/* Platform form controls. Linked from _Layout so any page can opt in.
 *
 * Two layouts, same control chrome:
 *   .sw-form-vertical    — label above the control, each field a .sw-form-field, and
 *                          the layout spaces them. Safe on a whole form or modal.
 *                          Source: GuestListConfirmation / RequestWorkflow/List filters.
 *   .sw-form-horizontal   — settings form. Each .sw-form-field is a row: 120px
 *                          right-aligned label, then .sw-form-controls holding the
 *                          control. Same layout as Event/CreateUpdate.
 *
 * Markup keeps Bootstrap's .form-control / .form-select / .form-label /
 * .form-check-inline. The wrappers do not restyle every field in the app.
 *
 * Colour, type, and control size come from tokens.css. The label column
 * (120px) and horizontal row gap (20px) stay as literals — they have no
 * token and must not snap onto the 4px scale. */

.sw-form-vertical .form-control,
.sw-form-vertical .form-select,
.sw-form-horizontal .form-control,
.sw-form-horizontal .form-select {
    border: 1px solid var(--sw-border-strong);
    border-radius: var(--sw-radius-sm);
    padding: var(--sw-control-padding-y) var(--sw-control-padding-x);
    font-size: var(--sw-font-size);
    height: var(--sw-control-height);
    color: var(--sw-text);
    background-color: var(--sw-surface);
}

.sw-form-vertical .form-control::placeholder,
.sw-form-horizontal .form-control::placeholder {
    color: var(--sw-text-subtle);
    opacity: 1;
}

/* The pickers' chevron, centred in the pickers' --sw-combobox-indicator-width rail, so a native
 * select ends exactly as SingleSelect and the multi-selects do. The right padding is that rail, so
 * the arrow never sits on the last letters. The icon is drawn 12px square.
 *
 * Full width, like .form-control and every picker. Bootstrap already says width: 100%, but
 * styles.css sets select { width: auto !important }, which shrinks a select to its longest option
 * and beats any rule without !important. Only an !important can answer it; this one is scoped to
 * the two layouts, so it outweighs that bare select selector and the legacy views keep theirs. */
.sw-form-vertical .form-select,
.sw-form-horizontal .form-select {
    width: 100% !important;
    padding-right: var(--sw-combobox-indicator-width);
    background-image: var(--sw-combobox-chevron-icon);
    background-position: right calc((var(--sw-combobox-indicator-width) - 12px) / 2) center;
    background-size: 12px 12px;
}

.sw-form-vertical textarea.form-control,
.sw-form-horizontal textarea.form-control {
    height: auto;
}

/* The pickers (@Html.MultiSelect, @Html.GroupedMultiSelect) render as a .sw-reveal-panel.
 * Shared/form-row.css sizes and shows that panel inside .sw-form; these are the same three
 * jobs for the two layouts here. Full width, like .form-control - Select2 writes a pixel
 * width inline, hence the !important. aria-hidden="true" is how the partials say the panel
 * is not in use, so it must not be on screen. */
.sw-form-vertical .sw-reveal-panel .select2-container,
.sw-form-horizontal .sw-reveal-panel .select2-container {
    display: block;
    width: 100% !important;
}

.sw-form-vertical .sw-grouped-multi-select-root,
.sw-form-horizontal .sw-grouped-multi-select-root {
    max-width: none;
}

.sw-form-vertical .sw-reveal-panel[aria-hidden="true"],
.sw-form-horizontal .sw-reveal-panel[aria-hidden="true"] {
    display: none;
}

.sw-form-vertical .sw-grouped-multi-select-root > .sw-grouped-multi-select__hint,
.sw-form-horizontal .sw-grouped-multi-select-root > .sw-grouped-multi-select__hint {
    margin-top: var(--sw-space-1);
    font-size: var(--sw-font-size-xs);
    color: var(--sw-text-subtle);
}

/* General rule 5 hides an inactive branch with the hidden attribute. Bootstrap 5.0.2 ships
 * no [hidden] rule (5.2 added one), so its .form-control { display: block } - and the
 * display rules below - beat the browser's own, and a hidden field stays on screen. */
.sw-form-vertical [hidden],
.sw-form-horizontal [hidden] {
    display: none !important;
}

.sw-form-vertical .form-control:focus,
.sw-form-vertical .form-select:focus,
.sw-form-horizontal .form-control:focus,
.sw-form-horizontal .form-select:focus {
    outline: none;
    border-color: var(--sw-border-focus);
    box-shadow: var(--sw-focus-ring);
}

.sw-form-vertical .form-control:disabled,
.sw-form-vertical .form-control[readonly],
.sw-form-vertical .form-select:disabled,
.sw-form-horizontal .form-control:disabled,
.sw-form-horizontal .form-control[readonly],
.sw-form-horizontal .form-select:disabled {
    background-color: var(--sw-surface-disabled);
}

/* Error node is only in the DOM when there is an error, so show it.
 * Covers radios too, where .is-invalid is nested and ~ .invalid-feedback
 * never matches. */
.sw-form-vertical .invalid-feedback,
.sw-form-horizontal .invalid-feedback {
    display: block;
}

/* An invalid field, however it was marked. Razor's ValidationMessageFor renders
 * span.field-validation-error and marks the control .input-validation-error, not
 * Bootstrap's .invalid-feedback / .is-invalid; the unobtrusive client adapter is not in
 * the project, so that is the server round trip. Both shapes look the same here, so a
 * Razor form needs no mapping script. The border has to be restated: the control rule
 * above sets the whole border and would otherwise beat Bootstrap's red one. Legacy
 * styles.css floats .field-validation-error at 100% width; undone for these layouts. */
.sw-form-vertical .field-validation-error,
.sw-form-horizontal .field-validation-error,
.sw-form-vertical .invalid-feedback,
.sw-form-horizontal .invalid-feedback {
    display: block;
    float: none;
    width: auto;
    margin: var(--sw-space-1) 0 0;
    font-size: var(--sw-font-size-xs);
    color: var(--sw-danger);
}

.sw-form-vertical .form-control.is-invalid,
.sw-form-horizontal .form-control.is-invalid,
.sw-form-vertical .form-select.is-invalid,
.sw-form-horizontal .form-select.is-invalid,
.sw-form-vertical .form-control.input-validation-error,
.sw-form-horizontal .form-control.input-validation-error,
.sw-form-vertical .form-select.input-validation-error,
.sw-form-horizontal .form-select.input-validation-error {
    border-color: var(--sw-danger);
}

.sw-form-vertical .form-text,
.sw-form-horizontal .form-text {
    margin-top: var(--sw-space-1);
    font-size: var(--sw-font-size-xs);
    color: var(--sw-text-subtle);
}

/* ---------- vertical: space between fields ----------
 *
 * Each field is a .sw-form-field, the same element as a horizontal row, and fields side by
 * side are a Bootstrap .row of columns. Every field or row after the first in its container
 * is pushed down. ~ rather than +, so a hidden input between two fields (the anti-forgery
 * token) does not cancel the gap.
 *
 * A row's own vertical gutter is swapped for row-gap. Bootstrap spaces wrapped columns with
 * a negative margin on the row and a positive one on each column, and its default gutter is
 * a unitless 0, which makes any calc() against it invalid; a margin above the row would
 * then double up with the columns' own on a .g-3 row. With the gutter at 0px, a .g-3 and a
 * .gx-3 row space alike, and a column that wraps on a phone sits one gap below. */
.sw-form-vertical .row {
    --bs-gutter-y: 0px;
    row-gap: var(--sw-space-4);
    /* responsive.css, from Bootstrap 2, zeroes .row's left margin below 767px, which
       pushes the columns half a gutter right of the fields around them on a phone. */
    margin-left: calc(var(--bs-gutter-x) * -.5);
}

/* A column may be the field itself. Columns side by side share a top edge, and row-gap
   already spaces them when they wrap, so the gap is only between rows and loose fields. */
.sw-form-vertical :is(.sw-form-field, .row) ~ :is(.sw-form-field, .row):not(.row > *) {
    margin-top: var(--sw-space-4);
}

/* ---------- label: same chrome, both layouts ---------- */

.sw-form-vertical .form-label,
.sw-form-horizontal .form-label {
    display: block;
    font-size: var(--sw-font-size);
    font-weight: var(--sw-font-weight-bold);
    margin-bottom: var(--sw-space-1);
}

.sw-form-vertical .form-check-label,
.sw-form-horizontal .form-check-label {
    font-size: var(--sw-font-size);
    font-weight: normal;
    margin-bottom: 0;
}

/* Vertical radios: flex, not Bootstrap's float gutter. Event UserFeedback
 * (and other .new-layout-wrapper pages) set `* { float: none !important }`,
 * which knocks the input out of .form-check's padding-left slot. */
.sw-form-vertical .form-check {
    display: flex;
    align-items: flex-start;
    padding-left: 0;
    min-height: auto;
    margin-bottom: var(--sw-space-1);
}

/* Not align-items:center — that centres the box on a wrapped label's whole block,
 * not its first line. The top margin centres it on that line instead:
 * (1.5 line-height - 1em box) / 2. */
.sw-form-vertical .form-check .form-check-input,
.sw-form-vertical .form-check-inline .form-check-input {
    float: none;
    margin: .25em var(--sw-space-2) 0 0;
}

.sw-form-vertical .form-check-inline {
    display: inline-flex;
    align-items: flex-start;
    margin-right: var(--sw-space-legacy);
    margin-bottom: var(--sw-space-1);
}

/* ---------- switch ----------
 *
 * Bootstrap's .form-switch presentation of a checkbox, in platform colour. It is a
 * checkbox and nothing else: same markup, same .form-check-label, same semantics. Use it
 * where the thing it controls changes immediately and visibly on the same screen - a
 * reveal, a filter, a preference. Anything that only takes effect on save stays a
 * checkbox, because a switch that has not done anything yet reads as a lie.
 *
 * Size is Bootstrap's own (2em x 1em = 28x14 at --sw-font-size), which is already on the
 * scale, so it is not restated here. The layout above already fixes the part Bootstrap
 * gets wrong under .sw-form-vertical: the switch relies on .form-switch's 2.5em left
 * padding and a negative margin to sit the input in the gutter, and the flex row replaces
 * both with a plain 8px gap.
 *
 * ADOPTED FROM: ViewRequest.cshtml carried an unscoped
 * `.form-switch .form-check-input:checked { background-color:#2ED158 }` - a fourth green
 * (--sw-primary is #2fb52a, --ea-success #2fb52b), leaking from one view's style block to
 * every switch on any page that loaded it. That is what this entry replaces.
 *
 * CONTRAST - inherits the open question at the foot of tokens.css, deliberately rather
 * than by picking a different green. The checked track is 2.71:1 against white, under the
 * 3:1 non-text bar, the same shortfall --sw-primary has on .btn-success. It is less acute
 * here than on a button: Bootstrap also moves the knob from left to right, so the state is
 * carried by position as well as colour and general rule 9 is satisfied without it. When
 * --sw-primary is resolved this resolves with it. Do not fix it locally. */
.sw-form-vertical .form-switch .form-check-input:checked,
.sw-form-horizontal .form-switch .form-check-input:checked {
    background-color: var(--sw-primary);
    border-color: var(--sw-primary);
}

/* Every control reachable by keyboard has a visible focus state - general rule 7. Scoped
 * to the switch so checkboxes and radios keep Bootstrap's, which is not this component's
 * call to change. */
.sw-form-vertical .form-switch .form-check-input:focus,
.sw-form-horizontal .form-switch .form-check-input:focus {
    border-color: var(--sw-border-focus);
    box-shadow: var(--sw-focus-ring);
}

/* Locked checkbox, radio or switch. aria-disabled, not disabled: readonly does nothing on
 * them, and disabled drops them from the tab order, so the reason in the help text is never
 * reached (general rule 6). This is Bootstrap's own :disabled look, which it only gives the
 * attribute. The click that would change it is cancelled in script. Focus still draws, on
 * purpose. */
.sw-form-vertical .form-check-input[aria-disabled="true"],
.sw-form-horizontal .form-check-input[aria-disabled="true"],
.sw-form-vertical .form-check-input[aria-disabled="true"] ~ .form-check-label,
.sw-form-horizontal .form-check-input[aria-disabled="true"] ~ .form-check-label {
    opacity: .5;
    cursor: not-allowed;
}

/* ---------- horizontal: label beside the control, right-aligned ----------
 *
 * Same row as Event/CreateUpdate and the rest of .form-horizontal:
 *   .form-horizontal .control-label { width:120px; text-align:right }
 *       (styles.css:464-470)
 *   .new-layout-wrapper--create .control-group .controls { width:100% }
 *       (styles.css:6864-6866)
 * The label column is a fixed 120px and must not grow. If it does, extra
 * width sits in the label, text-align:right packs the copy (and then the
 * controls) against the right edge — the Add/edit custom form field layout
 * below 1200px, when the sidebar has gone.
 * Stacking is a container query so inventory frames (~520px) still show the
 * row, while a phone-width form does not. */

.sw-form-horizontal {
    container-type: inline-size;
    container-name: sw-form;
}

.sw-form-horizontal .sw-form-field {
    display: flex;
    flex-wrap: nowrap;
    justify-content: flex-start;
    align-items: flex-start;
    gap: var(--sw-space-3);
    margin-bottom: 20px;
}

.sw-form-horizontal .sw-form-field:last-child {
    margin-bottom: 0;
}

.sw-form-horizontal .sw-form-field > .form-label {
    flex: 0 0 120px;
    width: 120px;
    max-width: 120px;
    margin-bottom: 0;
    padding-top: 6px;
    text-align: right;
}

/* The control column stops at --sw-form-control-max-width, the cap .sw-form already uses (form-row.css),
 * so a settings form on a wide page doesn't stretch every input across it. */
.sw-form-horizontal .sw-form-field > .form-control,
.sw-form-horizontal .sw-form-field > .form-select,
.sw-form-horizontal .sw-form-controls {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
    max-width: var(--sw-form-control-max-width);
}

/* First line centred in a control-height slot, so a check lines up with the row label
 * and a wrapped label grows downward. Same first-line reasoning as the vertical rule. */
.sw-form-horizontal .form-check,
.sw-form-horizontal .form-check-inline {
    display: flex;
    align-items: flex-start;
    min-height: var(--sw-control-height);
    padding-top: calc((var(--sw-control-height) - var(--sw-control-line-height)) / 2);
    padding-left: 0;
    margin-bottom: 0;
}

.sw-form-horizontal .form-check-inline {
    display: inline-flex;
    margin-right: var(--sw-space-legacy);
}

.sw-form-horizontal .form-check .form-check-input,
.sw-form-horizontal .form-check-inline .form-check-input {
    float: none;
    margin: .25em var(--sw-space-2) 0 0;
}

.sw-form-horizontal .sw-form-controls > .form-control,
.sw-form-horizontal .sw-form-controls > .form-select {
    width: 100%;
    max-width: 100%;
}

/* More than one control in the column: the follow-on (revealed text, "specific"
 * picker) sits under the checkbox or radios, full width. */
.sw-form-horizontal .sw-form-controls > .form-control:not(:first-child),
.sw-form-horizontal .sw-form-controls > .form-select:not(:first-child) {
    display: block;
    margin-top: 10px;
}

/* Narrow form: label above, left-aligned — the shared .form-label chrome.
 * A container query adds no specificity, so each selector repeats the
 * .sw-form-horizontal prefix of the row rules above and wins on source order.
 * Without it the label keeps flex: 0 0 120px, which in a column is a 120px
 * height, and stays 120px wide and right-aligned. */
@container sw-form (max-width: 420px) {
    .sw-form-horizontal .sw-form-field {
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: stretch;
        gap: var(--sw-space-1);
    }

    .sw-form-horizontal .sw-form-field > .form-label {
        flex: none;
        width: auto;
        max-width: none;
        margin-bottom: var(--sw-space-1);
        padding-top: 0;
        text-align: left;
    }

    .sw-form-horizontal .sw-form-field > .form-control,
    .sw-form-horizontal .sw-form-field > .form-select,
    .sw-form-horizontal .sw-form-field > .sw-form-controls {
        width: 100%;
    }
}
