/* ===================================================================================================
   PreemptiveScheduler control skin (feature K) — the ONE input/select/textarea/check look. A control
   opts in by carrying .ps-control wherever it is written (FormField slots, FilterBar children, page
   markup); the explicit class beats selector-context magic and reads at the call site. LAYOUT (widths,
   grid spans) stays the consuming pattern's job — see FormField.razor.css for the fill-the-field rule.
   Unlayered (not in @layer ps-*) so the class skin sits at normal author-cascade weight, beating the
   ps-base element defaults by class specificity. --ps-font-size-input is the ≥16px iOS no-zoom floor.
   =================================================================================================== */

.ps-control:where(input:not([type="checkbox"]):not([type="radio"]), select, textarea) {
    min-block-size: var(--ps-control-height);
    padding-block: var(--ps-space-1);
    padding-inline: var(--ps-space-3);
    border: 1px solid var(--ps-color-border-strong);
    border-radius: var(--ps-radius-md);
    background: var(--ps-color-surface-raised);
    color: var(--ps-color-text);
    font-family: inherit;
    font-size: var(--ps-font-size-input);
    line-height: var(--ps-line-dense);
}

.ps-control::placeholder {
    color: var(--ps-color-text-faint);
}

/* WCAG 2.5.8-sized check controls, custom-drawn so checked vs unchecked is UNAMBIGUOUS in both schemes. The native
   UA checkbox renders an unchecked box as a grey-filled square in the dark scheme (it reads as checked/indeterminate),
   so we replace the native paint (appearance:none) with an explicit outline-empty (unchecked) / accent-filled-with-glyph
   (checked) look on the theme tokens. The glyph is centered via the grid placement and the :checked ::before. */
.ps-control:where([type="checkbox"], [type="radio"]) {
    appearance: none;
    inline-size: var(--ps-target-min);
    block-size: var(--ps-target-min);
    flex: none;
    margin: 0;
    /* Unchecked: an empty box/circle on the raised surface with a strong border — clearly NOT filled. */
    border: 1px solid var(--ps-color-border-strong);
    background: var(--ps-color-surface-raised);
    cursor: pointer;
    display: inline-grid;
    place-content: center;
    transition:
        background-color var(--ps-motion-fast) var(--ps-ease),
        border-color var(--ps-motion-fast) var(--ps-ease);
}

.ps-control:where([type="checkbox"]) {
    border-radius: var(--ps-radius-sm);
}

.ps-control:where([type="radio"]) {
    border-radius: var(--ps-radius-full);
}

/* Checked: the accent fill plus a drawn glyph (a check for the box, a dot for the radio) — unmistakably ON. */
.ps-control:where([type="checkbox"], [type="radio"]):checked {
    background: var(--ps-color-accent);
    border-color: var(--ps-color-accent);
}

/* The glyph is sized from the TARGET TOKEN, not in percent: the box is a grid container whose single track is
   auto-sized, so a percentage resolves against an indefinite grid area and collapses the glyph to nothing — the
   filled box then reads the same checked, indeterminate, or (for a radio) selected, which is precisely the
   distinction these marks exist to draw. calc() off the same token keeps them scaling with the coarse-pointer
   target size. */
.ps-control:where([type="checkbox"]):checked::before {
    content: "";
    inline-size: calc(var(--ps-target-min) * 0.6);
    block-size: calc(var(--ps-target-min) * 0.6);
    background: var(--ps-color-on-accent);
    /* A check mark drawn from the on-accent color (a clipped tick) so it reads in both schemes and scales with the box. */
    clip-path: polygon(14% 44%, 0 60%, 40% 100%, 100% 22%, 84% 8%, 38% 70%);
}

.ps-control:where([type="radio"]):checked::before {
    content: "";
    inline-size: calc(var(--ps-target-min) * 0.45);
    block-size: calc(var(--ps-target-min) * 0.45);
    border-radius: var(--ps-radius-full);
    background: var(--ps-color-on-accent);
}

/* Indeterminate (the tri-state parent of a checkbox tree, e.g. the candidate-GPU picker's cluster/node boxes):
   the accent fill with a drawn DASH — unmistakably "some, not all". `indeterminate` is a DOM property with no
   attribute form, so Blazor stamps it over interop (site.js setIndeterminate); this rule is what paints it,
   since appearance:none above discards the UA's native dash. */
.ps-control:where([type="checkbox"]):indeterminate {
    background: var(--ps-color-accent);
    border-color: var(--ps-color-accent);
}

.ps-control:where([type="checkbox"]):indeterminate::before {
    content: "";
    inline-size: calc(var(--ps-target-min) * 0.55);
    block-size: 2px;
    border-radius: var(--ps-radius-full);
    background: var(--ps-color-on-accent);
    clip-path: none;
}

.ps-control:where([type="checkbox"], [type="radio"]):focus-visible {
    outline: 2px solid var(--ps-color-focus);
    outline-offset: 2px;
}

.ps-control:where([type="checkbox"], [type="radio"]):disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

/* ===================================================================================================
   The .ps-button family is GLOBAL, not scoped, because TWO primitives wear it: Button (a <button>) and
   LinkButton (a real <a href>, for navigations that must support middle-click / new-tab). A scoped sheet
   would only attach to one component's element. Unlayered for the same reason .ps-control is — the class
   skin must outrank the ps-base <a>/<button> element defaults by specificity.
   =================================================================================================== */
.ps-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ps-space-2);
    border: 1px solid transparent;
    border-radius: var(--ps-radius-md);
    font-family: inherit;
    font-weight: var(--ps-weight-medium);
    line-height: var(--ps-line-dense);
    white-space: nowrap;
    cursor: pointer;
    transition:
        background-color var(--ps-motion-fast) var(--ps-ease),
        border-color var(--ps-motion-fast) var(--ps-ease),
        color var(--ps-motion-fast) var(--ps-ease);
}

/* LinkButton resets: an <a> brings link defaults (underline, link color) that must yield to the variants. */
a.ps-button--link {
    text-decoration: none;
}

.ps-button:focus-visible {
    outline: 2px solid var(--ps-color-focus);
    outline-offset: 2px;
}

.ps-button:disabled,
.ps-button--link[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.55;
}

/* --- Sizes (both tokens bump to the 44px tier on coarse pointers). --- */
.ps-button--medium {
    min-block-size: var(--ps-control-height);
    padding-inline: var(--ps-space-3);
    font-size: var(--ps-text-sm);
}

.ps-button--small {
    min-block-size: var(--ps-target-min);
    padding-inline: var(--ps-space-2);
    font-size: var(--ps-text-xs);
}

/* Icon-only buttons render square at their size's height. */
.ps-button--icon-only {
    padding-inline: 0;
    aspect-ratio: 1;
}

/* --- Variants. --- */
.ps-button--primary {
    background: var(--ps-color-accent);
    border-color: var(--ps-color-accent);
    color: var(--ps-color-on-accent);
}

.ps-button--primary:hover:not(:disabled):not([aria-disabled="true"]) {
    background: var(--ps-color-accent-emphasis);
    border-color: var(--ps-color-accent-emphasis);
}

.ps-button--secondary {
    background: var(--ps-color-surface-raised);
    border-color: var(--ps-color-border-strong);
    color: var(--ps-color-text);
}

.ps-button--secondary:hover:not(:disabled):not([aria-disabled="true"]) {
    background: var(--ps-color-surface-sunken);
}

.ps-button--ghost {
    background: transparent;
    color: var(--ps-color-accent);
}

.ps-button--ghost:hover:not(:disabled):not([aria-disabled="true"]) {
    background: var(--ps-color-accent-soft);
}

.ps-button--danger {
    background: var(--ps-color-danger);
    border-color: var(--ps-color-danger);
    color: var(--ps-color-on-danger);
}

.ps-button--danger:hover:not(:disabled):not([aria-disabled="true"]) {
    background: color-mix(in srgb, var(--ps-color-danger) 85%, var(--ps-color-text));
    border-color: color-mix(in srgb, var(--ps-color-danger) 85%, var(--ps-color-text));
}

/* The Busy spinner: rotation rides the motion tokens, so reduced-motion renders it static (the disabled
   state + aria-busy still convey progress). */
.ps-button__spinner {
    display: inline-flex;
    animation: ps-button-spin calc(var(--ps-motion-slow) * 3) linear infinite;
}

@keyframes ps-button-spin {
    to {
        transform: rotate(360deg);
    }
}
