/*
 * Forms.
 *
 * Every rule here exists to make a form usable without sight, without a mouse, or without JavaScript.
 * The three constraints agree far more often than they conflict.
 *
 * Structural decisions the markup must uphold, since CSS cannot:
 *
 *   * every field has a real `<label for>`. A placeholder is not a label — it disappears on the first
 *     keystroke, fails contrast in most browsers, and is not announced reliably;
 *   * an error message is tied to its field with `aria-describedby` and the field carries
 *     `aria-invalid="true"`. The red border below is the visual half of a signal whose other half is
 *     text, because colour alone fails WCAG 1.4.1;
 *   * required fields are marked in text, not with an asterisk whose meaning is explained elsewhere.
 */

.field {
    /* Block rather than flex, so a field can hold a label, a hint, a control and an error without the
       order being decided here. */
    display: block;
}

.field + .field {
    /* margin-top: var(--space-6); */
}

.field__label {
    display: block;
    margin-bottom: var(--space-2);
    font-weight: var(--weight-medium);
}

/* Hint text sits between the label and the control, so it is read before the field is entered rather
   than after — which is when it is useful. */
.field__hint {
    display: block;
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-ink-quiet);
    max-width: var(--measure);
}

.field__required {
    font-weight: var(--weight-normal);
    color: var(--colour-ink-quiet);
}

/*
 * Controls.
 *
 * Selected by type rather than by class, so a control cannot be added without picking up the styling —
 * and cannot silently lose its visible border, which is a contrast requirement rather than decoration.
 */
.input,
.textarea,
.select,
input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="date"],
textarea,
select {
    display: block;
    width: 100%;
    max-width: 32rem;
    min-height: 2.75rem;
    padding: var(--space-2) var(--space-3);

    background-color: var(--colour-surface);
    color: var(--colour-ink);
    border: var(--border-width) solid var(--colour-border-strong);
    border-radius: var(--radius-sm);

    /* Prevents the zoom-on-focus that mobile Safari applies to anything under 16px. */
    font-size: var(--text-base);
}

textarea {
    min-height: 8rem;
    line-height: var(--leading-body);
}

/* The arrow is the browser's own: a custom one would need an inline SVG background, and there is no
   inline anything in this application (ADR 0006). */
select {
    /* Room for the arrow at either end, so a right-to-left locale needs no override. */
    padding-inline-end: var(--space-6);
}

/* A focus ring on a bordered control needs the border to change too, otherwise the ring reads as the
   field having grown rather than as the field being active. */
.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    border-color: var(--colour-primary);
}

input::placeholder,
textarea::placeholder {
    /* Quiet, but still 4.5:1 — a placeholder holding an example format is content. */
    color: var(--colour-ink-quiet);
    opacity: 1;
}

input:disabled,
textarea:disabled,
select:disabled {
    background-color: var(--colour-surface-sunken);
    color: var(--colour-ink-quiet);
    cursor: not-allowed;
}

/* Checkboxes and radios keep their native size and are laid out beside their label rather than above. */
input[type="checkbox"],
input[type="radio"] {
    width: auto;
    min-height: 0;
    margin: 0;
    accent-color: var(--colour-primary);
}

/* A choice is a two-column grid, not a flex row: the control owns the first column and the label
   and its explanatory sentence stack in the second, so the sentence always starts at the same
   edge no matter how many lines the label runs to. A flex row would put the hint beside the
   label and let the three drift apart as soon as text wraps. */
.field--choice {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: var(--space-3);
    row-gap: var(--space-1);
    align-items: start;
}

/* Nudge the native control down to the optical middle of the label's first line. */
.field--choice input[type="checkbox"],
.field--choice input[type="radio"] {
    margin-top: 0.3rem;
}

.field--choice .field__label {
    grid-column: 2;
    margin-bottom: 0;
    font-weight: var(--weight-medium);
}

.field--choice .field__hint {
    grid-column: 2;
    margin-bottom: 0;
}

/* ---- Errors ---------------------------------------------------------------------------------- */

/*
 * Invalid state.
 *
 * Keyed on `aria-invalid` rather than a class. The attribute is what a screen reader reads, so styling on
 * the same hook means the two halves of the signal cannot drift apart — a field cannot look invalid
 * without being announced as invalid, or the reverse.
 *
 * `:invalid` is deliberately not used: it matches before the reader has typed anything, so a required
 * field is red on arrival.
 */
[aria-invalid="true"] {
    border-color: var(--colour-error);

    /* Two pixels of border rather than a colour change alone, so the state survives forced-colours
       mode. */
    border-width: 2px;
}

.field__error {
    display: block;
    margin-top: var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--colour-error);
    max-width: var(--measure);
}

/* Summary of every error on the form, rendered above it after a failed submission and given focus, so a
   screen reader user hears what went wrong instead of hunting for it field by field. */
.form-errors {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    background-color: var(--colour-error-surface);
    border-inline-start: var(--focus-width) solid var(--colour-error);
    border-radius: var(--radius-sm);
}

.form-errors__heading {
    margin-top: 0;
    font-size: var(--text-lg);
    color: var(--colour-error);
}

.form-errors__list {
    margin-top: var(--space-2);
    margin-bottom: 0;
}

/* ---- Actions --------------------------------------------------------------------------------- */

.form__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-7);
}

/* ---- Legacy aliases — auth views use .form-field instead of .field ------------------------- */

.form-field {
    display: block;
}

.form-field + .form-field {
    margin-top: var(--space-6);
}

.form-field__label {
    display: block;
    margin-bottom: var(--space-2);
    font-weight: var(--weight-medium);
    font-size: var(--text-sm);
    color: var(--colour-ink);
}

.form-field__input {
    display: block;
    width: 100%;
    min-height: 2.75rem;
    padding: var(--space-2) var(--space-3);
    background-color: var(--colour-surface);
    color: var(--colour-ink);
    border: var(--border-width) solid var(--colour-border-strong);
    border-radius: var(--radius-sm);
    font-size: var(--text-base);
    font-family: inherit;
}

.form-field__input:focus {
    outline: none;
    border-color: var(--colour-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--colour-focus) 25%, transparent);
}

.form-field__hint {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-xs);
    color: var(--colour-ink-quiet);
}

.form-field__error {
    display: block;
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--colour-error);
}

.form-field--error .form-field__input {
    border-color: var(--colour-error);
    border-width: 2px;
}

/* ---- Admin form aliases — views use .form-group, .form-label, .form-actions, .form-help ---- */

.form-group {
    margin-bottom: var(--space-4);
}

.form-label {
    display: block;
    margin-bottom: var(--space-1);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--colour-ink);
}

.form-help {
    font-size: var(--text-xs);
    color: var(--colour-ink-quiet);
    margin-top: var(--space-1);
}

.form-actions {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

.inline-form {
    display: inline;
}
