/* Shared form primitives — the ONE set of classes every module's forms build on (coding-standards
   §3/§4): a page never re-declares "what a text input looks like". A module adds a local override
   class alongside these ONLY for something genuinely its own (e.g. documents' file-input reset) —
   never a full copy of the same declarations under a new name. Layout uses flex-wrap, not media
   queries, so a form reflows at any width without a breakpoint per module. Token-driven (§12). */

.platform-form {
    display: flex;
    flex-direction: column;
    gap: var(--platform-space-md, 1rem);
    max-width: 40rem;
}

/* A form that OWNS a full-width layout inside itself (M-111: the two-column user editor). The default
   40rem measure is the right reading width for a single stack of fields, but wrong when the form's body
   is an `<x-platform::two-column>` that must span the page and let each column set its own measure — so
   the split modifier lifts the cap. The per-column stacking is handled by `.platform-form__fields`. */
.platform-form--split {
    max-width: none;
}

/* A vertical stack of fields with the same rhythm as `.platform-form`, for when the fields are NOT direct
   children of the form (e.g. nested inside a two-column card) and so can't inherit the form's own gap.
   Layout only — no max-width; the containing column already sets the measure. */
.platform-form__fields {
    display: flex;
    flex-direction: column;
    gap: var(--platform-space-md, 1rem);
}

.platform-form__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--platform-space-md, 1rem);
    margin: 0;
    padding: 0;
    border: 0;
}

.platform-form__field {
    display: flex;
    flex-direction: column;
    gap: var(--platform-space-xs, 0.25rem);
    min-width: 0;
}

/* The grow/shrink/basis triplet is a MAIN-AXIS sizing instruction, so it only means "share the row's
   width" when the field's direct parent is a `.platform-form__row` (a row-direction flex container).
   A standalone field's direct parent is `.platform-form` itself, which is COLUMN-direction — there,
   the same `flex: 1 1 12rem` would mean "grow to fill the form's height", stretching every unwrapped
   field (title, textareas, multi-selects) with a large empty gap. Scoping to the row keeps it correct
   in both places without a modifier per context. */
.platform-form__row > .platform-form__field {
    flex: 1 1 12rem;
}

/* max-width, not flex-basis: a cap works identically whether the field sits in a row (it grows via the
   rule above, capped here) or stands alone (no growth to begin with, just narrower than 100%) — one
   declaration, no context scoping needed. */
.platform-form__field--narrow {
    max-width: 10rem;
}

.platform-form__field--tight {
    max-width: 6rem;
}

/* An INLINE field: label and control on ONE line, the control sized to its content rather than the column.
   For a short, self-explanatory value — a count, a size, a limit — where the stacked default wastes a line and
   `--narrow` is actively worse: capping the whole FIELD at 10rem also caps the LABEL, so a label of any length
   ("Maximum file size (KB)") wraps to two or three ragged lines above a small box. Here the label keeps its
   natural width and the CONTROL is the thing that is narrow.

   `flex-wrap` is the mobile-first escape hatch: on a viewport too narrow for label + control side by side, the
   row wraps and it degrades to the ordinary stacked field rather than squeezing either part. */
.platform-form__field--inline {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--platform-space-sm, 0.5rem);
}

/* The label must not be shrunk into a wrap by the control beside it — it sizes to its text and holds. */
.platform-form__field--inline .platform-form__label {
    flex: 0 0 auto;
}

/* The control gives up the field-filling `width: 100%` of the stacked default and takes only what the value
   needs. `width: auto` alone would let a number input keep its (generous) intrinsic width, so cap it. */
.platform-form__field--inline .platform-form__input {
    width: auto;
    max-width: 8rem;
}

/* A hint under an inline field belongs on its own line, not wedged between label and control: give it the
   full row so the pair above it stays intact. */
.platform-form__field--inline .platform-form__hint {
    flex: 1 0 100%;
}

.platform-form__label {
    font-weight: 600;
}

.platform-form__required {
    color: var(--platform-color-error-text, #c0392b);
}

.platform-form__input {
    width: 100%;
    /* Belt-and-suspenders against horizontal body overflow at phone width: width:100% already sizes
       the control to its field, but min-width:0 stops a control with an intrinsic minimum (date/number
       spinners, some selects) from forcing the field — and thus the row — wider than the viewport, and
       max-width:100% guards anything that reverts to width:auto. */
    min-width: 0;
    max-width: 100%;
    box-sizing: border-box;
    /* Vertical padding on its own density knob (M-084) so fields sit ~80% as tall; horizontal padding
       keeps the --space-sm inset (the M-074 look). */
    padding: var(--platform-input-padding-y, 0.35rem) var(--platform-space-sm, 0.5rem);
    font: inherit;
    color: var(--platform-color-text, #1f2328);
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #d0d7de);
    border-radius: var(--platform-radius-sm, 0.25rem);
}

.platform-form__input--error {
    border-color: var(--platform-color-error, #cf222e);
}

/* Native single-line <select> (M-252). A plain `<select class="platform-form__input">` otherwise keeps the
   OS's own chrome — its own arrow, padding and height — so it looks unstyled beside a SlimSelect control on the
   same row (e.g. the access panel's level select next to the people-picker). `appearance: none` strips that
   chrome so the select rides the SAME border/radius/height/font tokens as the text inputs above — and therefore
   matches the SlimSelect `.ss-main`, which maps to the very same tokens (slimselect-theme.css). Height matches
   because the shared `.platform-form__input` padding/font already sizes it to ~`--platform-input-height`.

   The caret is drawn from `currentColor` (two linear-gradient triangles meeting as a downward chevron), NOT an
   SVG data-URI: a background SVG data-URI renders in isolation and cannot read `currentColor` or our theme
   tokens, so its arrow would carry one baked colour and go invisible on a dark surface — the exact failure this
   card guards against. `currentColor` is the control's text colour (`--platform-color-text`), so the caret
   re-tints with EVERY theme, light or dark, by construction — no per-theme rule to keep in step (§7/§12). We set
   `background-image` (a longhand), never the `background` shorthand, so the surface colour from the base rule is
   preserved; error/muted states keep working because they touch border/background-color, not the caret.

   Scoped to `select…:not([multiple]):not([size])`: a `<select multiple>` or one with a `size` is a scrolling
   list box, not a dropdown, and must keep its native rendering. SlimSelect hides the native <select> it enhances
   with an inline `display:none` (which outranks this rule) and paints its own `.ss-main` <div> (no
   `.platform-form__input` class), so this rule can neither leak into an enhanced control nor show through the
   hidden original. Focus follows the browser's default outline, exactly like the text inputs above. */
select.platform-form__input:not([multiple]):not([size]) {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    /* Right gutter so the value never runs under the caret drawn below. */
    padding-inline-end: 1.75em;
    background-image:
        linear-gradient(45deg, transparent 50%, currentColor 50%),
        linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position:
        right 0.85em center,
        right 0.55em center;
    background-size: 0.3em 0.3em;
    background-repeat: no-repeat;
}

/* A number field whose value is a free-form amount (e.g. a contract's monetary value) gains nothing from
   the browser's up/down spinner — it steps by `step` (cents here), which is noise, not help. This modifier
   strips the spinner while keeping type="number" (so the native numeric keyboard + numeric validation
   stay). Applied PER FIELD, never globally, so a legitimately steppable integer (e.g. a směrnice's
   validity-days) keeps its spinner. */
.platform-form__input--no-spinner {
    -moz-appearance: textfield;
    appearance: textfield;
}

.platform-form__input--no-spinner::-webkit-outer-spin-button,
.platform-form__input--no-spinner::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* Empty date fields: an unset <input type="date"> shows the browser's date-format hint (e.g.
   "mm/dd/yyyy"), which reads like stray content. The `platform-date--empty` marker (toggled by
   DateInputHelper from the field's value) hides that hint while the field is empty AND unfocused, so
   it renders truly blank; :focus brings the format back for typing and a set value clears the marker.
   Cross-browser, because the hint lives in different places: WebKit/Blink (Chrome/Edge/Safari) paint
   it in the ::-webkit-datetime-edit shadow tree, so we transparent-fill the control AND that pseudo;
   Firefox has NO such pseudo and paints the hint as the input's own text, so the input-level rule is
   what covers it there (and doubles as the WebKit fallback via inheritance). The calendar picker icon
   keeps its own colour so it stays visible + clickable. Transparent fill (not visibility:hidden)
   preserves field height. */
input[type="date"].platform-date--empty:not(:focus) {
    color: transparent;
    -webkit-text-fill-color: transparent;
}

input[type="date"].platform-date--empty:not(:focus)::-webkit-datetime-edit {
    color: transparent;
    -webkit-text-fill-color: transparent;
}

input[type="date"].platform-date--empty:not(:focus)::-webkit-calendar-picker-indicator {
    -webkit-text-fill-color: initial;
    opacity: 1;
}

.platform-form__textarea {
    resize: vertical;
}

.platform-form__hint {
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text-muted, #57606a);
}

.platform-form__error {
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-error-text, #c0392b);
}

/* A group of fields that are ONE answer (M-220's reminder schedule: a preset + days-before-the-end + the
   notification date they produce). Drawn as a bordered <fieldset> with a legend above it, so the relationship is
   visible — without it the three read as three unrelated inputs and a preset silently overwriting a hand-typed
   date looks like a bug. The fieldset is a plain BLOCK and holds the grid row inside it: a legend inside a grid/
   flex container becomes one of its items and gets squeezed into a column beside the first field. Token-driven,
   so it re-skins with every theme. */
.platform-form__group {
    display: block;
    margin-block-end: var(--platform-space-md, 1rem);
    padding: var(--platform-space-xs, 0.25rem) var(--platform-space-md, 1rem) var(--platform-space-sm, 0.5rem);
    border: 1px solid var(--platform-color-border, #d0d7de);
    border-radius: var(--platform-radius-md, 0.375rem);
}

.platform-form__group-legend {
    float: none;
    width: auto;
    max-width: 100%;
    margin: 0;
    padding-inline: var(--platform-space-xs, 0.25rem);
    font-size: var(--platform-font-size-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.4;
    color: var(--platform-color-text-muted, #57606a);
}

/* A field that is currently read-only because the state makes it meaningless (M-220: the days-before-the-end
   field on a record with no end). It must NOT be `disabled` — a disabled input submits nothing, so the user's
   answer would be silently dropped — so it is read-only, and this says so visually. */
.platform-form__input--muted {
    background-color: var(--platform-color-surface-muted, #f6f8fa);
    color: var(--platform-color-text-muted, #57606a);
    cursor: not-allowed;
}

/* An <option> that cannot be picked in the current state (M-220: "N days before the end" on a record with no
   end). The browsers' own `[disabled]` option rendering is inconsistent — some platforms grey it, some do not,
   which half-signals and invites the click — so the state is stated explicitly here. Options that are not the
   record's own stored one are additionally taken out of the list by the controller (`hidden`), leaving this to
   style the one case that must stay visible: an existing record whose stored schedule is no longer possible. */
.platform-form__option--unavailable {
    color: var(--platform-color-text-muted, #57606a);
    font-style: italic;
}

/* Themeable checkbox (M-074) — the shared `<x-platform::checkbox>`. The real <input> is drawn from
   scratch (`appearance: none`) so its look is ours, not the browser's: a token-bordered box on the
   surface colour that fills with the teal accent and shows a white checkmark when checked. Every value is
   a --platform-* token, so it inverts cleanly under `:root[data-theme="dark"]` with no extra rules. The
   checkmark is a background SVG (white stroke = --platform-color-on-accent) revealed only when checked. */
.platform-checkbox {
    display: inline-flex;
    align-items: center;
    gap: var(--platform-space-xs, 0.25rem);
    cursor: pointer;
}

.platform-checkbox__input {
    appearance: none;
    -webkit-appearance: none;
    flex: 0 0 auto;
    width: 1.15rem;
    height: 1.15rem;
    margin: 0;
    background-color: var(--platform-color-surface, #ffffff);
    background-position: center;
    background-repeat: no-repeat;
    background-size: 0.7rem;
    border: 1px solid var(--platform-color-border, #d0d7de);
    border-radius: var(--platform-radius-sm, 0.25rem);
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.platform-checkbox__input:hover {
    border-color: var(--platform-color-accent, #16a085);
}

.platform-checkbox__input:checked {
    background-color: var(--platform-color-accent, #16a085);
    border-color: var(--platform-color-accent, #16a085);
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Cpath%20fill='none'%20stroke='%23ffffff'%20stroke-width='2.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20d='M3.5%208.5l3%203%206-6'/%3E%3C/svg%3E");
}

.platform-checkbox__input:focus-visible {
    outline: 2px solid var(--platform-color-accent, #16a085);
    outline-offset: 1px;
}

/* Bare checkbox (M-184): the visible caption is supplied elsewhere (e.g. a table column header), so the
   inline label text is visually hidden but kept in the DOM for assistive tech — the box reads correctly
   to screen readers while the cell shows just the control. */
.platform-checkbox--bare .platform-checkbox__label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.platform-form__submit {
    align-self: flex-start;
}

/* A horizontal row of form actions (e.g. a back link beside the submit), left-aligned and wrapping so
   it stays usable on a narrow screen. */
.platform-form__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--platform-space-sm, 0.5rem);
    align-items: center;
}

/* Validation-summary box (top-of-form error list), and the platform-admin "errors" box — same shape,
   one class family. */
.platform-form__errors {
    margin: 0 0 var(--platform-space-md, 1rem);
    padding: var(--platform-space-sm, 0.5rem) var(--platform-space-md, 1rem);
    color: var(--platform-color-error-text, #c0392b);
    background: var(--platform-color-error-surface, #fdeceb);
    border: 1px solid var(--platform-color-error, #cf222e);
    border-radius: var(--platform-radius-md, 0.5rem);
}

.platform-form__error-list {
    margin: 0;
    padding-left: var(--platform-space-lg, 1.5rem);
}

/* ── Phone (≤30rem / ~480px): stack side-by-side rows into one column ─────────────────────────────
   The `.platform-form__row` groups (contract/internal number, type/category/status, the date triplet,
   value/currency, the flag checkboxes) place their children side by side via `flex: 1 1 12rem`. On a
   phone that 12rem basis wraps two-or-three-up into cramped columns, so below the phone breakpoint we
   force one field per line for a comfortable tap width and to keep the row from ever exceeding the
   viewport.

   CRITICAL: we stack with flex-basis:100% and keep the row in ROW direction — NOT flex-direction:column.
   The fields carry `flex: 1 1 12rem`, a MAIN-AXIS instruction; flipping the row to column would reinterpret
   that 12rem as a HEIGHT and blow every field up to a 12rem-tall box (the flex-axis scoping trap called out
   in forms.css above). Basis:100% keeps the triplet a width, so each field simply wraps to its own row.
   The `--narrow`/`--tight` caps lift here so a short field (value, currency) spans the full width — a
   bigger, easier target on a phone. */
@media (max-width: 30rem) {
    .platform-form__row > .platform-form__field,
    .platform-form__row > .platform-checkbox {
        flex-basis: 100%;
    }

    .platform-form__field--narrow,
    .platform-form__field--tight {
        max-width: 100%;
    }
}
