/* =====================================================================
   UI STANDARDS LAYER  —  QA "OSM New Admin UI Common Observations"
   (Shripad Deshpande, ticket #2401, 2026-08-28)
   ---------------------------------------------------------------------
   One place that fixes the size, framing and alignment of every labelled
   form control, filter row, Action menu and pager in the application, so
   they no longer vary page by page.

   WHY THIS FILE EXISTS AND NOT app.css
   ------------------------------------
   126 pages ship a scoped `X.razor.css`. Blazor rewrites those rules to
   `.sel[b-xxxxx]`, which adds an attribute selector and therefore ALWAYS
   outranks the same selector written in app.css. app.css is also linked
   BEFORE the scoped bundle, so it loses ties too. Every page that
   re-declared `.form.cascade`, `.toolbar label` or `.form label select`
   in its own file was consequently free to invent its own column count,
   control height and label position — which is exactly what QA reported.

   This sheet is linked AFTER `OSM.Web.styles.css` (see index.html) and
   states the house standard once. `!important` is used deliberately and
   only on the properties that define the standard (box metrics, label
   position, column rhythm); everything else — colours, page-specific
   widths, one-off controls — is left to the pages. Tune the standard by
   editing the tokens below, not by adding rules to a page.
   ===================================================================== */

:root {
    /* control box */
    --ctl-h: 38px;                 /* every select / text input / date box */
    --ctl-radius: 9px;
    --ctl-fs: 13.5px;
    --ctl-px: 12px;

    /* field label (always ABOVE its control) */
    --fld-label-fs: 12px;
    --fld-label-lh: 18px;
    --fld-label-gap: 6px;
    /* Height of the whole label line. Anything that must sit on the same
       row as a control but has no label of its own (the Action menu) is
       pushed down by exactly this much. */
    --fld-label-block: 24px;       /* --fld-label-lh + --fld-label-gap */

    /* filter-row rhythm */
    --fld-col: 220px;              /* one dropdown column */
    --fld-gap-x: 16px;
    --fld-gap-y: 12px;
}

/* =====================================================================
   D] LABEL ABOVE THE CONTROL  +  B] ONE CONTROL BOX EVERYWHERE
   ---------------------------------------------------------------------
   Applies to any <label> that directly wraps its control. Checkbox and
   radio labels keep their inline "box then text" reading, and the pager
   and rich-text toolbars keep their own compact inline labels.
   ===================================================================== */

/* `.search-box` is itself a <label> wrapping its input (Components/SearchBox.razor), and file
   and colour inputs are click targets rather than form fields — all three keep their own
   layout. Checkbox and radio labels keep their inline "box then text" reading. */
label:not(.search-box):has(> select),
label:not(.search-box):has(> textarea),
label:not(.search-box):has(> input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="search"])),
label:not(.search-box):has(> .search-wrap),
label:not(.search-box):has(> .ac-wrap),
label:not(.search-box):has(> .osm-ctl) {
    /* `block`, not a column flexbox: the label's caption is a bare text node and the
       required marker is a <span> beside it, so as flex items they would become two
       stacked lines ("Course" above a lone red "*"). Block keeps the caption inline and
       the control — a block-level element below — still starts its own line. */
    display: block !important;
    min-width: 0;
    font-size: var(--fld-label-fs);
    line-height: var(--fld-label-lh);
    font-weight: 600;
    color: var(--muted);
}

/* Some pages write the caption as a SIBLING of the control inside a `.field` wrapper rather
   than wrapping it. Same caption metrics, so the two shapes read identically. */
.field > label, .field > .lbl {
    display: block;
    min-width: 0;
    font-size: var(--fld-label-fs);
    line-height: var(--fld-label-lh);
    font-weight: 600;
    color: var(--muted);
}
.field > label + select, .field > label + input { margin-top: var(--fld-label-gap) !important; }

/* The pager and the editor toolbar are horizontal strips, not forms —
   their labels stay on the control's line. */
.pager label:not(.search-box):has(> select),
.pager label:not(.search-box):has(> input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="search"])),
.head-actions label:not(.search-box):has(> select),
.head-actions label:not(.search-box):has(> input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="search"])),
.rte-toolbar label:not(.search-box):has(> select),
.rte-toolbar label:not(.search-box):has(> input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="color"]):not([type="search"])) {
    display: inline-flex !important;
    flex-direction: row !important;
    align-items: center !important;
    flex: none !important;
    white-space: nowrap !important;
    gap: 6px !important;
}
/* ...and their controls do not open a line of their own. */
.pager label > select, .pager label > input,
.head-actions label > select, .head-actions label > input,
.rte-toolbar label > select, .rte-toolbar label > input { margin-top: 0 !important; }

/* One box for every value-entry control that lives in a field block. */
label:not(.search-box):has(> select) > select,
label:not(.search-box) > input[type="date"], label:not(.search-box) > input[type="number"],
label:not(.search-box) > input[type="text"], label:not(.search-box) > input:not([type]),
.form select, .form input[type="date"], .form input[type="number"], .form input[type="text"],
.toolbar select, .toolbar input[type="date"], .toolbar input[type="number"], .toolbar input[type="text"],
.filters select, .filter-grid select, .filter-bar select, .form-grid select, .panel-grid select,
.field > select, .field > input[type="date"], .field > input[type="number"], .field > input[type="text"] {
    display: block !important;
    width: 100% !important;
    box-sizing: border-box !important;
    height: var(--ctl-h) !important;
    min-height: var(--ctl-h) !important;
    padding-top: 0 !important;
    padding-bottom: 0 !important;
    padding-left: var(--ctl-px) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--ctl-radius) !important;
    background-color: var(--surface-2) !important;
    color: var(--ink);
    font-size: var(--ctl-fs) !important;
    font-family: inherit !important;
    margin-top: var(--fld-label-gap) !important;
}

/* A required control keeps the dashed marker from app.css — restate the
   border here or the rule above would flatten it back to a solid line. */
label:not(.search-box):has(> select) > select:required,
.form select:required, .form input:required,
.toolbar select:required { border-style: dashed !important; }
label:not(.search-box):has(> select) > select:required:focus,
.form select:required:focus, .form input:required:focus,
.toolbar select:required:focus { border-style: solid !important; }

/* Text areas share the frame but never the fixed height. */
label:has(> textarea) > textarea, .form textarea {
    display: block !important;
    width: 100% !important;
    box-sizing: border-box !important;
    height: auto !important;
    min-height: calc(var(--ctl-h) * 2) !important;
    padding: 9px var(--ctl-px) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--ctl-radius) !important;
    font-size: var(--ctl-fs) !important;
    font-family: inherit !important;
}

/* The pager's own controls opt out of the field metrics (they are a
   compact strip), but still share the frame and radius. */
.pager select, .pager input {
    height: 32px !important;
    min-height: 32px !important;
    width: auto !important;
    font-size: 12.5px !important;
}

/* Focus and disabled treatments, stated once. */
.form select:focus, .form input:focus, .toolbar select:focus, .toolbar input:focus,
label:not(.search-box):has(> select) > select:focus {
    outline: 2px solid var(--accent); outline-offset: -1px;
}
.form select:disabled, .form input:disabled,
.toolbar select:disabled, .toolbar input:disabled,
label:not(.search-box):has(> select) > select:disabled { opacity: .6; cursor: default; }

/* =====================================================================
   B] FILTER ROWS: ONE COLUMN RHYTHM
   ---------------------------------------------------------------------
   `auto-fill` (not `auto-fit`) is the point: a row with two dropdowns
   gets two columns of the SAME width as a row with four, instead of two
   half-width ones. The control no longer sizes itself from the longest
   option, so the row reads the same on every page.
   ===================================================================== */

.form.cascade, .form-grid, .filter-grid, .filter-bar, .panel-grid {
    display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(var(--fld-col), 1fr)) !important;
    gap: var(--fld-gap-y) var(--fld-gap-x) !important;
    align-items: end !important;
}
/* A field asked to span two columns keeps that intent. */
.form.cascade > .span-2, .form-grid > .span-2, .filter-grid > .span-2 { grid-column: span 2; }

/* Toolbars stay flex — they also carry buttons, counts and search boxes —
   but each labelled field in one takes the standard column width so the
   dropdowns line up with the grid pages. */
.toolbar > label:has(> select),
.toolbar > label:has(> input:not([type="checkbox"]):not([type="radio"])) {
    flex: 0 1 var(--fld-col) !important;
}
.toolbar { align-items: flex-end !important; row-gap: var(--fld-gap-y); }
/* Anything in a filter toolbar that is NOT a field (buttons, counts,
   search) still centres against the control line rather than the label. */
.toolbar > .btn, .toolbar > button, .toolbar > .count, .toolbar > .search-box,
.toolbar > .search, .toolbar > .head-actions { align-self: flex-end; }

@media (max-width: 560px) {
    .form.cascade, .form-grid, .filter-grid, .filter-bar, .panel-grid {
        grid-template-columns: 1fr !important;
    }
    .toolbar > label:has(> select),
    .toolbar > label:has(> input:not([type="checkbox"]):not([type="radio"])) { flex: 1 1 100% !important; }
}

/* =====================================================================
   C] ACTION MENU ON THE FILTER LINE
   ---------------------------------------------------------------------
   The Action button has no label of its own, so aligning the row on its
   centre floated it between the labels and the controls, and a second
   filter row moved it again. It is now top-aligned and pushed down by
   exactly one label line, which puts it on the control's line — the
   Stream | Degree | A.Year line — and keeps it there whatever the
   dropdowns below do.
   ===================================================================== */

.action-and-filters { display: flex !important; align-items: flex-start !important; gap: var(--fld-gap-x); }
.action-and-filters > .action-menu,
.action-and-filters > .action-spacer { flex: 0 0 88px !important; margin-top: var(--fld-label-block) !important; }
.action-and-filters > .form, .action-and-filters > .toolbar { flex: 1; min-width: 0; margin-bottom: 0; }

/* Pages that drop the Action menu straight into a filter toolbar get the
   same treatment, so it sits on the dropdown line there too. */
.toolbar:has(> label > select) > .action-menu { margin-top: var(--fld-label-block) !important; align-self: flex-start; }

/* One Action button, one size, on every page. */
.action-menu > .action-toggle {
    width: 100%;
    min-width: 88px;
    height: var(--ctl-h) !important;
    box-sizing: border-box;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
}

/* =====================================================================
   F] PAGINATION: ONE SIZE, ONE THEME
   ---------------------------------------------------------------------
   The pager is already a shared component, but 20 pages still carried a
   dead `.pager` block in their scoped css and the control heights drifted
   with whatever `select`/`btn` rules a page happened to define. Fixed
   here so every pager is the same object.
   ===================================================================== */

.pager {
    display: flex !important;
    align-items: center !important;
    flex-wrap: wrap;
    gap: 16px !important;
    padding: 14px 2px 2px !important;
    justify-content: flex-start !important;
    font-size: 12.5px;
}
.pager .nums { display: flex; align-items: center; gap: 4px; }
.pager .btn {
    height: 32px !important;
    min-width: 32px !important;
    padding: 0 10px !important;
    border-radius: 8px !important;
    font-size: 12.5px !important;
    font-weight: 600 !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    border: 1px solid var(--border) !important;
    background: transparent;
    color: var(--ink);
}
.pager .btn.num { min-width: 34px !important; padding: 0 8px !important; }
.pager .btn:hover:not(:disabled) { background: var(--track); }
.pager .btn.num.on { background: var(--accent) !important; border-color: var(--accent) !important; color: #fff !important; }
.pager .btn:disabled { opacity: .5; cursor: default; }
.pager .ellipsis { color: var(--faint); padding: 0 2px; user-select: none; }
.pager .goto input { width: 56px !important; text-align: center; }
.pager .total, .pager .count, .pager .pageinfo { color: var(--faint); font-size: 12.5px; }

/* =====================================================================
   E] MANDATORY MARKER
   ---------------------------------------------------------------------
   The asterisk always trails its label text, never leads it, and reads
   the same in both themes (colour already in app.css).
   ===================================================================== */
.req { margin-left: 3px; margin-right: 0; white-space: nowrap; }
