/* =============================================================================
   ems-tokens.css — THE design system. One file, one vocabulary.
   -----------------------------------------------------------------------------
   WHY THIS EXISTS

   The product had 14 stylesheets, 317 views carrying their own <style> block,
   and six competing names for "a KPI tile" (.kpi, .bi-kpi, .ep-kpi, .spf-kpi,
   .vra-kpi, .small-box). Nothing decided what anything looked like, so:

     - .bi-kpi was restyled in v1.298.0 and rendered NOTHING. Zero views use it.
     - A portrait font fix lost to a per-view `#DataGrid th { font-size: 7px }`,
       because an ID beats any class layer however many !importants it carries.
     - Print orientation was broken by Bootstrap's own `@page { size: a3 }`,
       three layers down in a vendor file nobody owned.

   Each of those is the same failure: no single source of truth. A "premium
   redesign" layered on top would have been the 15th stylesheet, half-applying.

   SO THE RULES ARE:
     1. Every colour, size, space and radius is a token here. No literals in views.
     2. Components are emitted by ui_helper.php, not hand-written per view — a
        class can be ignored, a helper cannot.
     3. A converted view DELETES its <style> block. Overriding it is not enough:
        ID-scoped rules win, which is exactly how the 7px bug survived.

   The vocabulary is lifted from the college G1 screens (college_payroll_dashboard
   and siblings) because that is already the best-looking, tightest thing in the
   product. Promoting what works beats inventing a seventh dialect.
   ============================================================================= */

:root {
	/* ---- ink + surface ------------------------------------------------- */
	--u-ink:        #0f172a;   /* primary text                              */
	--u-ink-2:      #334155;   /* body text in tables                       */
	--u-muted:      #475569;   /* secondary text, labels                    */
	--u-soft:       #64748b;   /* captions, placeholders, disabled          */
	--u-line:       #e8edf3;   /* borders                                   */
	--u-line-2:     #f1f5f9;   /* interior rules, row separators            */
	--u-bg:         #f5f7fb;   /* page canvas                               */
	--u-surface:    #ffffff;   /* cards                                     */
	--u-surface-2:  #f8fafc;   /* hover / subtle fills                      */

	/* ---- accent. INDIGO. ------------------------------------------------
	       ⚠ THIS REVERSES THE "BLUE, NO PURPLE" RULE THAT STOOD HERE.
	       User decision 2026-09-03: one indigo for every control in the
	       system. It supersedes the earlier blue; the note is kept so nobody
	       re-applies the old rule from memory.

	       Measured against white: #5B4BE8 is 5.81:1, BETTER than the 5.17:1
	       the blue gave, so this is not a contrast trade. The dark step is
	       7.43:1 and the tint carries accent text at 5.02:1.

	       ⚠ CHANGE THE COLOUR HERE AND NOWHERE ELSE. The estate had FOUR
	       accents running in parallel when this was set — #2563eb, #4f46e5,
	       #5b4be8, #6366f1 — which is exactly what these tokens exist to
	       stop. A new hardcoded hex is a fifth. ------------------------- */
	--u-primary:      #5b4be8;
	--u-primary-d:    #4a3bd0;
	--u-primary-tint: #eeedfd;

	/* ---- semantic. Separate from the accent on purpose: status must not
	       change meaning when branding does. ------------------------------- */
	--u-ok:       #16a34a;  --u-ok-tint:    #e9f8ef;
	--u-warn:     #b45309;  --u-warn-tint:  #fff7ed;
	--u-danger:   #dc2626;  --u-danger-tint:#fef2f2;
	--u-info:     #0891b2;  --u-info-tint:  #ecfeff;

	/* ---- type. A scale, not a pile of arbitrary sizes. ------------------ */
	--u-font: 'Inter Tight', 'Inter', 'Segoe UI', system-ui, -apple-system, Arial, sans-serif;
	--u-fs-page:  18px;   /* page title            */
	--u-fs-card:  13.5px; /* card title            */
	--u-fs-body:  12.5px; /* body, inputs, buttons */
	--u-fs-table: 12.5px; /* table cells           */
	--u-fs-label: 12px;   /* form labels           */
	--u-fs-micro: 10.5px; /* column heads, captions, badges */

	/* ---- space. 4px base. --------------------------------------------- */
	--u-s1: 4px;  --u-s2: 8px;  --u-s3: 12px;
	--u-s4: 16px; --u-s5: 24px; --u-s6: 32px;

	/* ---- shape + elevation. One hairline, one soft shadow. A second
	       stacked shadow is what made the old cards read heavy. ---------- */
	--u-radius:    14px;
	--u-radius-sm: 8px;
	--u-radius-xs: 6px;
	--u-shadow:       0 1px 2px rgba(16, 24, 40, .03);
	--u-shadow-hover: 0 4px 14px rgba(16, 24, 40, .06);
	--u-ring:         0 0 0 3px rgba(91, 75, 232, .16);   /* the accent, matched to --u-primary */

	--u-control-h: 34px;   /* every single-line input, select and button    */
}


/* =============================================================================
   COMPONENTS — emitted by ui_helper.php. Do not hand-write this markup.
   ============================================================================= */

.ui-scope { font-family: var(--u-font); color: var(--u-ink); }
.ui-scope *, .ui-scope *::before, .ui-scope *::after { box-sizing: border-box; }


/* ---- page header ------------------------------------------------------ */
.ui-page-head {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: var(--u-s3);
	flex-wrap: wrap;
	margin-bottom: var(--u-s4);
}

.ui-page-head h1 {
	margin: 0;
	font-size: var(--u-fs-page);
	font-weight: 800;
	letter-spacing: -.015em;
	color: var(--u-ink);
	line-height: 1.2;
}

.ui-page-head p {
	margin: 2px 0 0;
	font-size: var(--u-fs-body);
	color: var(--u-muted);
}

.ui-page-head .ui-page-tools { display: flex; align-items: center; gap: var(--u-s2); flex-wrap: wrap; }


/* ---- card ------------------------------------------------------------- */
.ui-card {
	background: var(--u-surface);
	border: 1px solid var(--u-line);
	border-radius: var(--u-radius);
	box-shadow: var(--u-shadow);
	margin-bottom: var(--u-s4);
	transition: border-color .15s, box-shadow .15s;
}

.ui-card:hover { border-color: #dbe3ee; box-shadow: var(--u-shadow-hover); }

/* ⚠ SHADED, ALWAYS (design rule, 2026-09-15). A plain white card header lets the title float in
   the same plane as the content beneath it, and on a page of stacked cards the eye loses where one
   ends. The inset bottom rule is drawn as a shadow rather than a border so it costs no height. */
.ui-card-head {
	background: linear-gradient(180deg, #fcfcfd 0%, #f3f4f6 100%);
	box-shadow: inset 0 -1px 0 0 #dde0e4;
	border-radius: var(--u-radius) var(--u-radius) 0 0;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--u-s3);
	flex-wrap: wrap;
	padding: var(--u-s3) var(--u-s4);
	border-bottom: 1px solid var(--u-line-2);
}

.ui-card-head h2 {
	margin: 0;
	font-size: var(--u-fs-card);
	font-weight: 800;
	letter-spacing: 0;
	color: var(--u-ink);
}

.ui-card-head .ui-card-sub { display: block; font-size: var(--u-fs-micro); font-weight: 500; color: var(--u-soft); margin-top: 1px; }
.ui-card-tools { display: flex; align-items: center; gap: var(--u-s2); flex-wrap: wrap; }
.ui-card-body { padding: var(--u-s4); }
.ui-card-body.is-flush { padding: 0; }


/* ---- form fields ------------------------------------------------------ */
.ui-field { margin-bottom: var(--u-s3); }

.ui-field > label {
	display: block;
	margin: 0 0 var(--u-s1);
	font-size: var(--u-fs-label);
	font-weight: 600;
	color: var(--u-ink-2);
}

.ui-field .ui-req { color: var(--u-danger); font-weight: 700; }

.ui-scope .ui-input,
.ui-scope select.ui-input {
	display: block;
	width: 100%;
	height: var(--u-control-h);
	padding: 0 10px;
	border: 1px solid #dde5ef;
	border-radius: var(--u-radius-sm);
	background: var(--u-surface);
	color: var(--u-ink-2);
	font-family: inherit;
	font-size: var(--u-fs-body);
	outline: none;
	transition: border-color .15s, box-shadow .15s;
}

.ui-scope textarea.ui-input { height: auto; min-height: 76px; padding: 8px 10px; }
.ui-scope .ui-input:focus { border-color: var(--u-primary); box-shadow: var(--u-ring); }
.ui-scope .ui-input::placeholder { color: #b4c0cf; }
.ui-scope .ui-input.is-invalid { border-color: var(--u-danger); }
.ui-field .ui-error { display: block; margin-top: var(--u-s1); font-size: var(--u-fs-micro); color: var(--u-danger); }
.ui-field .ui-hint  { display: block; margin-top: var(--u-s1); font-size: var(--u-fs-micro); color: var(--u-soft); }


/* ---- buttons ---------------------------------------------------------- */
.ui-scope .ui-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	height: var(--u-control-h);
	padding: 0 14px;
	border: 1px solid transparent;
	border-radius: var(--u-radius-sm);
	font-family: inherit;
	font-size: var(--u-fs-body);
	font-weight: 600;
	line-height: 1;
	cursor: pointer;
	text-decoration: none;
	white-space: nowrap;
	transition: background .15s, border-color .15s, color .15s;
}

.ui-scope .ui-btn-primary { background: var(--u-primary); color: #fff; }
.ui-scope .ui-btn-primary:hover { background: var(--u-primary-d); color: #fff; }

.ui-scope .ui-btn-default { background: var(--u-surface); border-color: #cbd5e1; color: var(--u-ink-2); }
.ui-scope .ui-btn-default:hover { background: var(--u-surface-2); border-color: #64748b; color: var(--u-ink); }

.ui-scope .ui-btn-danger { background: var(--u-danger); color: #fff; }
.ui-scope .ui-btn-danger:hover { background: #b91c1c; color: #fff; }

.ui-scope .ui-btn-sm { height: 28px; padding: 0 10px; font-size: var(--u-fs-micro); }
.ui-scope .ui-btn-icon { width: 28px; height: 28px; padding: 0; }
.ui-scope .ui-btn:focus-visible { outline: 2px solid var(--u-primary); outline-offset: 2px; }
.ui-scope .ui-btn[disabled] { opacity: .55; cursor: not-allowed; }


/* ---- table ------------------------------------------------------------
   Header is a rule, not a filled band: a grey bar behind every column head
   is the heaviest thing on a data screen and competes with the data. */
.ui-table-wrap { overflow-x: auto; }

.ui-scope .ui-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--u-fs-table);
	margin: 0;
}

.ui-scope .ui-table thead th {
	padding: var(--u-s2) 11px;
	border-bottom: 2px solid var(--u-line);
	background: transparent;
	color: var(--u-soft);
	font-size: var(--u-fs-micro);
	font-weight: 700;
	letter-spacing: .04em;
	text-transform: uppercase;
	text-align: left;
	white-space: nowrap;
	vertical-align: middle;
}

.ui-scope .ui-table tbody td {
	padding: var(--u-s2) 11px;
	border-bottom: 1px solid var(--u-line-2);
	color: var(--u-ink-2);
	vertical-align: middle;
}

.ui-scope .ui-table tbody tr:last-child td { border-bottom: 0; }

/* ⚠ ALTERNATING, NOT PLAIN (design rule, 2026-09-15). Every row below a header banded
   white / --u-surface-2. On the dense grids this product is mostly made of, an unbanded table
   makes the eye lose its line across a wide row — which is how a figure gets read against the
   wrong student. Hover shares the band colour deliberately: two tones, not three. */
.ui-scope .ui-table tbody tr:nth-child(even) td { background: var(--u-surface-2); }
.ui-scope .ui-table tbody tr:hover td { background: var(--u-surface-2); }

/* Money and counts line up. Lining figures are why a column of numbers reads
   as a column instead of as ragged text. */
.ui-scope .ui-table .u-num,
.ui-scope .ui-table th.u-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ui-scope .ui-table .u-mid, .ui-scope .ui-table th.u-mid { text-align: center; }
.ui-scope .ui-table tfoot td { border-top: 2px solid var(--u-line); font-weight: 700; color: var(--u-ink); }

.ui-empty { padding: var(--u-s6) var(--u-s4); text-align: center; color: var(--u-soft); font-size: var(--u-fs-body); }


/* ---- badge ------------------------------------------------------------ */
/* ⚠ SQUARE, NOT A PILL (design rule, 2026-09-15). Every chip, tag, badge, pill and count marker
   in the product takes --u-radius-sm. `border-radius: 999px` is forbidden: a fully rounded status
   marker reads as a notification dot rather than as a value, and the two must not look alike. */
.ui-badge {
	display: inline-block;
	padding: 3px 8px;
	border-radius: var(--u-radius-sm);
	font-size: var(--u-fs-micro);
	font-weight: 700;
	line-height: 1.3;
	white-space: nowrap;
}

.ui-badge.is-ok     { background: var(--u-ok-tint);     color: var(--u-ok); }
.ui-badge.is-warn   { background: var(--u-warn-tint);   color: var(--u-warn); }
.ui-badge.is-danger { background: var(--u-danger-tint); color: var(--u-danger); }
.ui-badge.is-info   { background: var(--u-info-tint);   color: var(--u-info); }
.ui-badge.is-muted  { background: #f1f5f9;              color: var(--u-muted); }


/* ---- KPI tile ---------------------------------------------------------
   ONE definition, replacing six. Label leads and the number follows, which is
   the order a metric is looked for in; the icon is a corner glyph rather than
   a 40px chip on its own line eating half the tile's height. */
.ui-kpis { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); margin-bottom: var(--u-s4); }

.ui-kpi {
	display: flex;
	flex-direction: column;
	background: var(--u-surface);
	border: 1px solid var(--u-line);
	/* A KPI tile is a card and takes the card radius. 13px was a third value for no reason. */
	border-radius: var(--u-radius);
	box-shadow: var(--u-shadow);
	padding: 13px 14px;
	text-decoration: none;
	transition: border-color .15s, box-shadow .15s;
}

a.ui-kpi:hover { border-color: color-mix(in srgb, var(--u-accent, var(--u-primary)) 45%, var(--u-line)); box-shadow: 0 4px 12px rgba(16, 24, 40, .07); }
.ui-kpi-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--u-s2); margin-bottom: var(--u-s2); }
.ui-kpi-label { font-size: 11px; font-weight: 600; color: var(--u-muted); line-height: 1.3; }
.ui-kpi-icon {
	flex: none; width: 26px; height: 26px; border-radius: var(--u-radius-sm); margin-top: -1px;
	display: flex; align-items: center; justify-content: center; font-size: 13px;
	background: color-mix(in srgb, var(--u-accent, var(--u-primary)) 12%, #fff);
	color: var(--u-accent, var(--u-primary));
}
.ui-kpi-value { font-size: 21px; font-weight: 800; color: var(--u-ink); line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.ui-kpi-sub { font-size: 11px; color: var(--u-soft); margin-top: 5px; line-height: 1.25; }


/* ---- layout ----------------------------------------------------------- */
.ui-grid { display: grid; gap: var(--u-s4); }
@media (min-width: 992px) {
	.ui-grid.cols-2      { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ui-grid.cols-3      { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.ui-grid.split-1-2   { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
	.ui-grid.split-1-3   { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
}


/* ---- accessibility ---------------------------------------------------- */
.ui-scope a:focus-visible,
.ui-scope input:focus-visible,
.ui-scope select:focus-visible { outline: 2px solid var(--u-primary); outline-offset: 1px; }

@media (prefers-reduced-motion: reduce) {
	.ui-scope * { transition: none !important; animation: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   SYSTEM CONTROLS — one accent for every button, radio and checkbox.
   User decision 2026-09-03: indigo everywhere.

   ⚠ WHY THIS BLOCK HAS TO EXIST AT ALL.

   The accent tokens above only reach the surfaces WE wrote. The buttons a person actually
   presses come from the vendored Limitless theme, where `.btn-primary` is hardcoded Material
   blue #2196F3 — a fifth accent, on top of the four our own sheets carried. Nothing above
   touches it, so without this the tokens change the trim and leave every button blue.

   ⚠ NO `!important` ANYWHERE, AND THAT IS DELIBERATE.

   This file loads at position 32, after bootstrap (15) and components (18), so equal specificity
   already wins on order. The `body` prefix lifts each selector one class above the vendor rule so
   the override holds even if the load order is ever rearranged. `!important` would win too, and
   would then be unopposable by the module skins (ems-admin-skin, ems-enterprise) that
   legitimately restyle buttons inside their own screens.

   ⚠ SEMANTIC COLOURS ARE UNTOUCHED. Success, danger, warning and info keep their meaning: a
   delete button must not become the brand colour just because the brand changed.
   ═════════════════════════════════════════════════════════════════════════════════════════ */

/* ---- native controls -------------------------------------------------------------------
   One property does radio, checkbox, range and progress in every current browser, with no
   markup change and no sprite image. This is what actually answers "and radio buttons". */
input[type="checkbox"],
input[type="radio"],
input[type="range"],
progress {
	accent-color: var(--u-primary, #5b4be8);
}

/* ---- primary buttons -------------------------------------------------------------------- */
body .btn-primary {
	background-color: var(--u-primary, #5b4be8);
	border-color: var(--u-primary, #5b4be8);
	color: #fff;
}

body .btn-primary:hover,
body .btn-primary:focus,
body .btn-primary.focus {
	background-color: var(--u-primary-d, #4a3bd0);
	border-color: var(--u-primary-d, #4a3bd0);
	color: #fff;
}

/* Bootstrap's active state carries :not(:disabled):not(.disabled); matched here so the button
   does not flash back to blue on press — the one state people notice most. */
body .btn-primary:not(:disabled):not(.disabled):active,
body .btn-primary:not(:disabled):not(.disabled).active,
body .show > .btn-primary.dropdown-toggle {
	background-color: var(--u-primary-d, #4a3bd0);
	border-color: var(--u-primary-d, #4a3bd0);
	color: #fff;
}

body .btn-primary:focus,
body .btn-primary.focus,
body .btn-primary:not(:disabled):not(.disabled):active:focus {
	box-shadow: var(--u-ring, 0 0 0 3px rgba(91, 75, 232, .16));
}

/* ---- outline and link variants of the same button ---------------------------------------- */
body .btn-outline-primary {
	color: var(--u-primary, #5b4be8);
	border-color: var(--u-primary, #5b4be8);
}

body .btn-outline-primary:hover,
body .btn-outline-primary:not(:disabled):not(.disabled):active {
	background-color: var(--u-primary, #5b4be8);
	border-color: var(--u-primary, #5b4be8);
	color: #fff;
}

body .btn-link {
	color: var(--u-primary, #5b4be8);
}

body .btn-link:hover {
	color: var(--u-primary-d, #4a3bd0);
}

/* ---- the utility classes the product paints alongside the buttons ------------------------- */
body .bg-primary {
	background-color: var(--u-primary, #5b4be8);
	color: #fff;
}

body .text-primary {
	color: var(--u-primary, #5b4be8);
}

body .border-primary {
	border-color: var(--u-primary, #5b4be8);
}

/* ---- styled checkboxes and radios (Bootstrap custom-control / form-check) ------------------
   Limitless renders these as a ::before pseudo-element rather than the native input, so
   accent-color above cannot reach them. */
body .custom-control-input:checked ~ .custom-control-label::before,
body .form-check-input:checked {
	background-color: var(--u-primary, #5b4be8);
	border-color: var(--u-primary, #5b4be8);
}

body .custom-control-input:focus ~ .custom-control-label::before,
body .form-check-input:focus {
	box-shadow: var(--u-ring, 0 0 0 3px rgba(91, 75, 232, .16));
	border-color: var(--u-primary, #5b4be8);
}

/* ---- switches and the focused text input -------------------------------------------------- */
body .custom-switch .custom-control-input:checked ~ .custom-control-label::before {
	background-color: var(--u-primary, #5b4be8);
	border-color: var(--u-primary, #5b4be8);
}

body .form-control:focus,
body .custom-select:focus {
	border-color: var(--u-primary, #5b4be8);
	box-shadow: var(--u-ring, 0 0 0 3px rgba(91, 75, 232, .16));
}

/* ---- keyboard focus, everywhere ------------------------------------------------------------
   :focus-visible only, so a mouse click does not leave a ring behind but tabbing always shows
   where you are. */
body a:focus-visible,
body button:focus-visible,
body [role="button"]:focus-visible {
	outline: 2px solid var(--u-primary, #5b4be8);
	outline-offset: 2px;
}
