/*
    Inline field validation -- the one visual contract for every form in the app.

    Before this, a validation failure could reach the user four different ways: a browser alert, a
    toast slider, a summary block at the top of the form, or (on the public site only) a message
    under the field. The toast was the worst of them: it named the problem without naming the box,
    and it slid away while the user was still looking for it. Everything now lands under the field
    that caused it, and the toast is reserved for things that belong to the page rather than to a
    field -- "Saved", "Network error", "Server unavailable".

    Three sources write into the same element, so they all have to agree on the same classes:
      * asp-validation-for spans re-rendered by the server from ModelState;
      * jquery-validation-unobtrusive, which swaps field-validation-valid / field-validation-error;
      * wwwroot/js/field-validation.js, which uses .is-invalid for forms with no unobtrusive
        metadata (the JSON modals and the public forms).

    Pair with: <p class="field-error" data-valmsg-for="FieldName"></p>
*/

:root {
    --field-error-color: #BA1A1A; /* status-urgent, the back-office danger token */
    --field-error-ring: rgba(186, 26, 26, 0.18);
}

/*
    Collapsed rather than display:none. The element keeps its place in the flow, so showing a
    message expands it over 150ms instead of shoving everything below it down in a single frame --
    which is what made a long form jump under the pointer as errors appeared on submit.
*/
.field-error {
    display: block;
    max-height: 0;
    margin-top: 0;
    opacity: 0;
    overflow: hidden;
    /* start, not left: the same rule has to read correctly in Arabic. */
    text-align: start;
    color: var(--field-error-color);
    font-size: 0.8125rem;
    line-height: 1.35;
    letter-spacing: normal;
    text-transform: none;
    transition: max-height 0.15s ease-out, opacity 0.15s ease-out, margin-top 0.15s ease-out;
}

.field-error.is-invalid,
.field-error.field-validation-error {
    max-height: 6rem;
    margin-top: 0.25rem;
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .field-error {
        transition: none;
    }
}

/*
    The invalid state of the control itself.

    !important is doing real work here rather than papering over a specificity accident: every
    input in the app carries Tailwind utilities for its border and focus ring (border-border-subtle,
    focus:ring-slate-blue), the utility classes have the same specificity as anything written here,
    and the Play CDN injects them at runtime -- so source order is not something this file can rely
    on. Only the colours are overridden; widths and radii stay as they are, so marking a field
    invalid never moves the layout.
*/
.field-invalid.field-invalid,
.input-validation-error.input-validation-error {
    border-color: var(--field-error-color) !important;
}

.field-invalid.field-invalid:focus,
.field-invalid.field-invalid:focus-visible,
.field-invalid.field-invalid:focus-within,
.input-validation-error.input-validation-error:focus {
    border-color: var(--field-error-color) !important;
    outline: none;
    box-shadow: 0 0 0 3px var(--field-error-ring) !important;
}

/*
    Marks a wrapper instead of the control: a radio or checkbox group, a date pill whose border
    lives on the surround, or a TomSelect picker, whose real <select> is hidden and whose visible
    box is .ts-control inside the wrapper.
*/
.field-invalid-group.field-invalid-group,
.field-invalid-group.field-invalid-group .ts-control {
    border-color: var(--field-error-color) !important;
}
