/* =============================================================================
   cst-tokens.css — the single source of design tokens
   Built in Phase 2 Step 1; extended in Phase 3 Step 1.

   REPLACES templates/_project_css_vars.cfm and the ProjectDataValues
   Category='css' read. See docs/decisions.md D1.

   Load order: immediately after Tabler core, before any project stylesheet.
   Linked by templates/header.cfm, templates/admin_header.cfm and
   includes/header/company_header.cfm.

   STRUCTURE
     1. Brand tokens        --cst-*   semantic names, no raw colour names (D9)
     2. Typography          --cst-font-*, --cst-text-*, --cst-weight-*, …
     3. Spacing             --cst-space-*
     4. Radius / shadow / breakpoints / container / feedback surfaces
        + CHART SERIES PALETTE                                          (D22)
     -  DENSE TYPE SCALE    .cst-dense remaps the type tokens           (D15)
     5. Tabler bindings     the ONLY place --tblr-* is assigned
                            includes card flatness + floating elevation (D17)
     6. Compatibility rules the two real rules the old include emitted

   RULES FOR EDITING
     - Every token carries a one-line comment stating its role.
     - Nothing outside sections 5 and 6 may assign a --tblr-* variable.
       Section 5 holds the :root bindings; section 6 holds the few SCOPED
       ones a component needs (.btn-secondary, .cst-navbar), which cannot
       live at :root without applying everywhere.
     - No component may hardcode a colour. If a value has no token, add one here.
     - A shadow token names what it is FOR, not what it looks like. Surfaces are
       flat (D17); only floating things carry elevation.
     - `.cst-dense` may only REMAP tokens that already exist at :root. It must
       never introduce a name the root scope does not define, or a component
       outside a dense container will read an undefined value.
     - Dark mode is out of scope (D11). A [data-bs-theme="dark"] block would go
       after section 5; do not write one without a decision.
   ============================================================================= */


/* =============================================================================
   1. BRAND TOKENS
   ============================================================================= */

:root {

	/* --- Text -------------------------------------------------------------- */
	--cst-ink:                    #16263c;  /* Primary text; also the dark band surface. Was Brand Primary Color + Body Text Color (D3). */
	--cst-ink-soft:               #34486a;  /* Secondary text, lead copy, nav links; also the dark-band card border. */
	--cst-muted:                  #4f5d70;  /* Tertiary text: metadata, captions, timestamps. */

	/* --- Accent (the primary action colour) -------------------------------- */
	--cst-accent:                 #006624;  /* Primary action: buttons, links, focus ring, active states (D3). */
	--cst-accent-hover:           #004d1b;  /* Primary action, hover and active. */
	--cst-accent-pale:            #e8f3e0;  /* Tinted band and pale accent backgrounds. */

	/* --- Decorative brand colours ------------------------------------------
	   Deliberately NOT bound to state slots. Changing a state colour must never
	   change the homepage (D4). */
	--cst-eyebrow-green:          #7fbe41;  /* Brand light green: eyebrow on dark, price-line border. Was Success Color. */
	--cst-terracotta:             #ffb262;  /* Brand peach: star fills, dashed tag borders, warn pills. Was Warning Color. */
	--cst-terracotta-pale:        #fff0df;  /* Peach tint background. */
	--cst-terracotta-ink:         #8a4d00;  /* Peach-family text on light backgrounds. */
	--cst-gold:                   #7a5a12;  /* Rating numerals; tag border on dark (D10 — was two values one digit apart). */
	--cst-badge:                  #ffdf72;  /* Yellow badge background. */
	--cst-logo-blue:              #406bab;  /* Logo wordmark and tile links. */
	--cst-warm-text:              #7a4a12;  /* Warm-brown text on peach tints. */

	/* --- Surfaces ----------------------------------------------------------- */
	--cst-surface:                #fff;     /* Cards, panels, inputs, the header bar. */
	--cst-surface-muted:          #f9fafc;  /* Disabled inputs and recessed panels. */
	--cst-page-bg:                #fff;     /* Page background. White per D2 — was #faf6ee, which retires with Tier B. */
	--cst-band:                   #f2f2ec;  /* Alternating section band, warm off-white. */
	--cst-sand:                   #fff1e0;  /* Sand band background. */
	--cst-sand-line:              #f2d8b6;  /* Sand band border. */
	--cst-tint-band-border:       #cfe4bd;  /* Border for the pale-accent tinted band. */

	/* --- Borders ------------------------------------------------------------ */
	--cst-border:                 #d5d5c8;  /* Card, control and divider borders. Warm grey. */
	--cst-border-subtle:          #e4e4da;  /* Band rules and progress-track backgrounds. */

	/* --- Hero band ---------------------------------------------------------- */
	--cst-hero-band-top:          #fbfdf8;  /* Hero gradient, top stop. */
	--cst-hero-band-bottom:       #eaf3e2;  /* Hero gradient, bottom stop. */
	--cst-hero-band-border:       #d3e5c0;  /* Hero band bottom rule. */

	/* --- Dark band context --------------------------------------------------
	   Text and surface colours used inside .dark sections, where the background
	   is --cst-ink. */
	--cst-dark-surface:           #1f3350;  /* Card background inside a dark band. */
	--cst-dark-body-text:         #dbe2ec;  /* Paragraph text on dark. */
	--cst-dark-card-text:         #c9d3e0;  /* Card paragraph text on dark. */
	--cst-dark-sub-text:          #b6c1d2;  /* Sub-heading text on dark. */
	--cst-dark-muted-text:        #a9b6c9;  /* Metadata and captions on dark. */
	--cst-dark-icon:              #9ed36a;  /* Icon stroke on dark. */

	/* --- Dark green band context -------------------------------------------- */
	--cst-dark-green-card:        #0a7a30;  /* Card background inside a dark-green band. */
	--cst-dark-green-border:      #2f8f4e;  /* Card border, bar fill and stat rule on dark green. */
	--cst-dark-green-text:        #e2f1e7;  /* Paragraph text on dark green. */
	--cst-dark-green-stat:        #c6e6d0;  /* Stat label on dark green. */

	/* --- Accent band context ------------------------------------------------ */
	--cst-accent-band-text:       #dff0d4;  /* Paragraph text on the solid accent band. */
	--cst-accent-band-lead:       #bfdfa9;  /* Supporting text on the accent band. */
	--cst-accent-band-btn-hover:  #eef7e7;  /* Inverted primary button hover on the accent band. */

	/* --- Footer -------------------------------------------------------------- */
	--cst-footer-link:            #e4eaf3;  /* Footer link text. */
	--cst-footer-text:            #d6dfeb;  /* Footer body and bottom-bar text. */

	/* --- Shift-coverage rail (homepage narrative graphic) -------------------- */
	--cst-rail-label:             #7a2e00;  /* Rail row label and gap marker text. */
	--cst-segment-a-bg:           #eaf0f7;  /* Rail segment A background. */
	--cst-segment-a-text:         #31465e;  /* Rail segment A supporting text. */
	--cst-segment-c-bg:           #fdf6dc;  /* Rail segment C background. */
	--cst-segment-c-border:       #d9b52e;  /* Rail segment C border. */
	--cst-segment-c-text:         #6b5510;  /* Rail segment C supporting text. */
	--cst-segment-contrast-text:  #cde8d5;  /* Supporting text inside the continuous-coverage bar. */

	/* --- Misc ---------------------------------------------------------------- */
	--cst-logo-placeholder:       #9aa08e;  /* Partner-logo placeholder fill. */
	--cst-badge-pill-text:        #4a3a05;  /* Text on the yellow badge pill. */
	--cst-badge-text:             #fafaf7;  /* Text on solid badges. Off-white per D10 — was #f2f2ec, the band background reused as text. FLAGGED FOR REVIEW. */
	--cst-shadow-rgb:             28 29 31; /* Shadow and scrim base. Deliberately not --cst-ink: the comps use a warmer near-black for shadows. */


/* =============================================================================
   2. TYPOGRAPHY
   ============================================================================= */

	/* --- Families ------------------------------------------------------------ */
	--cst-font-sans:  Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;  /* The only UI family. Roboto de-duplicated (the comps listed it twice). */
	--cst-font-mono:  Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;  /* IDs, codes, log output. Upgraded from the bare `monospace` token. */

	/* --- Weights -------------------------------------------------------------
	   Loaded set is 400 / 500 / 700 / 900 (Step 4). The comps use 600 twice; it
	   is not loaded and maps to 700 in Phase 4 — see docs/decisions.md DF3. */
	--cst-weight-normal:   400;  /* Body copy. */
	--cst-weight-medium:   500;  /* Emphasised body, secondary labels. */
	--cst-weight-bold:     700;  /* Headings h3–h4, buttons, nav, labels. */
	--cst-weight-display:  900;  /* h1 and h2 only. */

	/* h4's rank. At root it is a size step above body so it needs nothing
	   extra; in `.cst-dense` it is the SAME size as body and leans on these
	   instead. Components read these rather than hardcoding, so one rule works
	   in both densities. */
	--cst-h4-weight:    var(--cst-weight-bold);    /* 700 */
	--cst-h4-tracking:  var(--cst-tracking-none);  /* 0 at root; .04em when dense. */

	/* --- Size scale -----------------------------------------------------------
	   Nine steps, collapsed from the comps' sixteen literal sizes.

	   WHY NINE AND NOT THE EIGHT THE DIRECTIVE PROPOSED
	   The display range needs three steps to keep h1 above h2 at BOTH
	   breakpoints (h1 34→44, h2 27→31). Collapsing display to two steps makes
	   h1 and h2 the same size on mobile and destroys the hierarchy. The UI range
	   is six steps and already merges one pair (see below).

	   MAPPING — every original size, and where it lands
	     12px → --cst-text-2xs    (unchanged)
	     13px → --cst-text-xs     (unchanged)
	     14px → --cst-text-sm     (unchanged)
	     15px → --cst-text-md     (unchanged)
	     16px → --cst-text-base   MERGED UP to 17px. The only deliberate merge in
	                              the UI range: 16px was body copy inside
	                              components (.btn, .tab, .bcard p, .rcard li,
	                              .step p, .tile p, .ftr a) while `body` was
	                              17px. Merging makes body copy one size.
	     17px → --cst-text-base   (unchanged — the comps' body size)
	     18px → --cst-text-lg     +1px  (h3, .lead)
	     19px → --cst-text-lg     (unchanged)
	     20px → --cst-text-lg     -1px  (.logo)
	     27px → --cst-text-xl     +1px  (h2 mobile)
	     28px → --cst-text-xl     (unchanged — .step .num)
	     30px → --cst-text-xl     -2px  (.stat b)
	     31px → --cst-text-2xl    +1px  (h2 desktop)
	     32px → --cst-text-2xl    (unchanged — .mcard .big)
	     34px → --cst-text-2xl    -2px  (h1 mobile)
	     44px → --cst-text-3xl    (unchanged — h1 desktop)

	   NOT SET HERE: Tabler's own body font-size stays at its default 0.875rem
	   (14px). The comps' 17px applies inside .cst-page only. Raising Tabler's
	   base would restyle every back-office page — 577 form labels in admin
	   alone — and Phase 2 does not restyle. Open question for Phase 3. */
	--cst-text-2xs:   0.75rem;    /* 12px — micro labels: tags, captions, flags. */
	--cst-text-xs:    0.8125rem;  /* 13px — eyebrow, pills, ratings, kickers. */
	--cst-text-sm:    0.875rem;   /* 14px — metadata, bylines, roles, small print. */
	--cst-text-md:    0.9375rem;  /* 15px — nav links, small buttons, stat labels. */
	--cst-text-base:  1.0625rem;  /* 17px — body copy, buttons, tabs. */
	--cst-text-lg:    1.1875rem;  /* 19px — h3, lead paragraphs, pull quotes. */
	--cst-text-xl:    1.75rem;    /* 28px — h2 mobile, step numerals, stat figures. */
	--cst-text-2xl:   2rem;       /* 32px — h2 desktop, h1 mobile, KPI figures. */
	--cst-text-3xl:   2.75rem;    /* 44px — h1 desktop. */
	--cst-text-caption: 0.75rem;  /* 12px — smallest permitted text. `.cst-dense` takes this to 11px. */

	/* --- Line heights ---------------------------------------------------------
	   MAPPING: 1→none; 1.15/1.22/1.25/1.28→tight; 1.35→snug;
	            1.45/1.5/1.55→normal; 1.6→relaxed. */
	--cst-leading-none:     1;     /* Large numerals only. */
	--cst-leading-tight:    1.25;  /* Headings. */
	--cst-leading-snug:     1.35;  /* Clamped card titles. */
	--cst-leading-normal:   1.5;   /* Dense body, list items, quotes. */
	--cst-leading-relaxed:  1.6;   /* Default body copy. */

	/* --- Letter spacing -------------------------------------------------------
	   MAPPING: -.03em→tight; 0/.01em/.02em→none; .04em→wide; .05em/.06em→wider.
	   Collapsing .05→.06 resolves the eyebrow (.06em) vs kicker (.05em)
	   inconsistency flagged in docs/audit/comp-tokens.md. */
	--cst-tracking-tight:  -0.03em;  /* Large tabular numerals. */
	--cst-tracking-none:   0;        /* Default. */
	--cst-tracking-wide:   0.04em;   /* Uppercase tags and rail labels. */
	--cst-tracking-wider:  0.06em;   /* Uppercase eyebrows and kickers. */


/* =============================================================================
   3. SPACING

   Ten steps. Seven are Tabler's own spacer scale; three are additions the comps
   genuinely need (marked ✚). Tabler ships 0 / 4 / 8 / 16 / 24 / 32 / 40px.

   MAPPING — all 32 literal values in the comps
     0                 → --cst-space-0   (0)
     1, 2, 3, 4, 5     → --cst-space-1   (4px)
     6, 7, 8, 9        → --cst-space-2   (8px)
     10, 11, 12, 13    → --cst-space-3   (12px)  ✚
     14, 16, 18        → --cst-space-4   (16px)
     20, 22            → --cst-space-5   (20px)  ✚
     24, 26, 28        → --cst-space-6   (24px)
     30, 32, 34        → --cst-space-7   (32px)
     38, 44, 48        → --cst-space-8   (40px)
     52, 56            → --cst-space-9   (56px)  ✚

   NAMED EXCEPTIONS — values that move by more than 4px, called out rather than
   silently rounded:
     48 → 40  (-8px)  .ftr padding-top; .teams__grid gap.
     28 → 24  (-4px)  .head margin-bottom, .railrow, .trustbar, .statrow.
                      This breaks the one spacing relationship the comps had:
                      .sec padding (56) was exactly twice .head margin (28).
                      After the collapse it is 56/24. Flagged; revisit in
                      Phase 3 if the section rhythm reads wrong.

   NOT SPACING — two literals are component dimensions and stay in the
   component: .drow .lbl width (64px) and .gap width (78px).
   ============================================================================= */

	--cst-space-0:  0;         /* Reset. */
	--cst-space-1:  0.25rem;   /*  4px — icon gaps, hairline offsets. */
	--cst-space-2:  0.5rem;    /*  8px — inline gaps, tight stacks. */
	--cst-space-3:  0.75rem;   /* 12px ✚ button gaps, small stacks, tab padding. */
	--cst-space-4:  1rem;      /* 16px — default stack and inline gap. */
	--cst-space-5:  1.25rem;   /* 20px ✚ grid gutter, card padding. */
	--cst-space-6:  1.5rem;    /* 24px — container gutter, section head margin. */
	--cst-space-7:  2rem;      /* 32px — large grid gaps. */
	--cst-space-8:  2.5rem;    /* 40px — footer padding, wide two-column gaps. */
	--cst-space-9:  3.5rem;    /* 56px ✚ section vertical rhythm (.sec). */

	/* The default gap between stacked things inside a container — card body
	   rows, form rows, list items. Points at a step rather than being one, so
	   `.cst-dense` can move the rhythm without touching the scale. */
	--cst-stack-gap:  var(--cst-space-4);  /* 16px at root; 12px when dense. */

	/* --- Component metrics (Phase 3 Step 5) ------------------------------------
	   Two components need a fixed height rather than one derived from their
	   content: a table row, because rows must align across a scroll boundary and
	   a sticky header, and a row-action button, because D19 makes it a square.
	   Both point at spacing steps so `.cst-dense` moves them together. */
	--cst-table-row-height:  var(--cst-space-8);  /* 40px at root; 32px when dense. */
	--cst-table-cell-pad-x:  var(--cst-space-4);  /* 16px at root; 12px when dense. */
	--cst-row-action-size:   var(--cst-space-7);  /* 32px square (D19). Same in both densities — a touch target does not shrink. */

	/* The back-office navbar's minimum bar height. Public's header is a fixed
	   72px (cst-header.css); company's was an inline `min-height: 60px` and
	   admin's was whatever Tabler's padding produced. Kept at 60px rather than
	   unified to 72px, because D35 changed the colour of those bars and not
	   their geometry — the heights are Step 7's business. */
	--cst-navbar-min-height: 60px;

	/* A bounded scrolling list — a long product or user list inside a card
	   that must not push the page. Two panes on the assign screens set
	   15rem and 380px inline; one height for both is the standardisation. */
	--cst-scroll-pane-max: 24rem;

	/* The fixed height of a course-card cover image, cropped to fill. A card
	   grid needs its images the same height or the cards misalign; this is
	   that height, not a spacing step. */
	--cst-card-img-height: 140px;

	/* The square thumbnail beside a course card's details, cropped to fill.
	   Sized so three cards still fit a large row with the image and the text
	   side by side; a fixed box, not a spacing step, because every card in the
	   grid has to agree on it or the titles stop lining up. */
	--cst-card-thumb-size: 88px;

	/* The photo-edit badge: the little camera button pinned to the corner of
	   an avatar on the profile page. Fixed pixel size because it overlays a
	   fixed-size avatar, not a step on the spacing scale. */
	--cst-photo-badge-size: 28px;

	/* The circular icon medallion (.cst-medallion). Larger than Tabler's
	   2.5rem avatar because it holds an icon, not initials. */
	--cst-medallion-size: 3rem;

	/* The fixed square a placeholder company logo occupies in the info
	   preview. Not a spacing step: it is an image box sized to match what
	   the header renders, and the header is the thing that fixes it. */
	--cst-logo-placeholder-size: 96px;

	/* The label gutter in a stacked table row (`.cst-table-stack`, below md).
	   Not a spacing step: it is a text column, sized so the longest real column
	   label in the application — "Licenses", "Last active", "Deactivated" — sits
	   on one line beside its value. Deliberately fixed rather than `max-content`
	   so every row's value starts at the same x and the block still scans as a
	   column. Same in both densities: the labels do not get shorter. */
	--cst-stack-label-width: 8.5rem;

	/* --- Measure ---------------------------------------------------------------
	   Maximum line length for readable prose, in `ch` so it tracks the font
	   rather than the viewport. Not part of the spacing scale — a measure is a
	   typographic constraint, not a gap.

	   The comps used five different ch values ad hoc: 34ch (footer blurb),
	   52ch (teams paragraph), 56ch (hero lead), 60ch (final CTA) and 78ch (rail
	   caption). These four steps cover them; 52ch and 60ch round to --md. */
	--cst-measure-xs:  34ch;  /* Sidebars, footer blurbs, narrow columns. */
	--cst-measure-sm:  44ch;  /* Empty-state body, help text, single-idea copy. */
	--cst-measure-md:  56ch;  /* The default for prose. Lead paragraphs, section intros. */
	--cst-measure-lg:  78ch;  /* Long captions under a diagram. The upper bound. */


/* =============================================================================
   4. RADIUS, SHADOW, BREAKPOINTS
   ============================================================================= */

	/* --- Radius ---------------------------------------------------------------
	   The comps' radius set is IDENTICAL to Tabler 1.0.0's: 4px default, 2px
	   small, pill. Tabler also ships 8px large, which the comps do not define
	   and which the previous token table had already adopted. No --tblr-*
	   radius override is therefore needed; these are aliases so our own
	   stylesheets can read a --cst-* name. */
	--cst-radius:       4px;     /* Buttons, cards, inputs, panels. */
	--cst-radius-sm:    2px;     /* Pills, tags, progress bars, focus outline. */
	--cst-radius-lg:    8px;     /* Large panels. Tabler's value; no comp source. */
	--cst-radius-pill:  100rem;  /* Fully rounded: search field, avatars, arrows. */

	/* --- Shadow ---------------------------------------------------------------
	   RESOLVED IN PHASE 3 (D17): surfaces are FLAT WITH A BORDER. Cards, panels,
	   tables and inputs carry a 1px border and no shadow, in every section.

	   Shadow is reserved for things that FLOAT ABOVE the page — an element that
	   is temporarily on top of other content and needs to read as detached.
	   If it is part of the page, it gets a border. If it sits over the page, it
	   gets a shadow. There is no third case.

	   Each token below names what it is FOR, not what it looks like. Do not
	   introduce a shadow without adding a role here first. */
	--cst-shadow-overlay:     0 2px 4px rgb(var(--cst-shadow-rgb) / 8%), 0 4px 12px rgb(var(--cst-shadow-rgb) / 8%);  /* FOR: dropdowns, popovers, tooltips. The comps' two-layer hover shadow, reused as the standard floating elevation. */
	--cst-shadow-modal:       0 8px 16px rgb(var(--cst-shadow-rgb) / 10%), 0 16px 48px rgb(var(--cst-shadow-rgb) / 14%);  /* FOR: modals and offcanvas panels — further from the page than a dropdown, so a longer, softer cast. */
	--cst-shadow-toast:       0 4px 8px rgb(var(--cst-shadow-rgb) / 10%), 0 8px 24px rgb(var(--cst-shadow-rgb) / 12%);  /* FOR: toasts. Between a dropdown and a modal: it floats, but it is not blocking. */
	--cst-shadow-hover:       var(--cst-shadow-overlay);  /* FOR: the comps' .card--hov lift on Tier A marketing cards ONLY. Not a back-office affordance — D17 makes those flat. */
	--cst-shadow-hover-dark:  0 4px 14px rgb(0 0 0 / 45%);  /* FOR: the same comp hover, inside a .dark band where the page behind is already dark. */

	/* Retired by D17. Kept for one phase so a stray reference fails loudly in
	   review rather than silently painting a shadow Phase 3 removed. */

	/* --- Breakpoints -----------------------------------------------------------
	   CSS cannot tokenise a media query, so these are documentation only.
	   Bootstrap's px breakpoints win (D5); the comps' 64rem is dropped.

	     sm    576px
	     md    768px   — comps' 48rem agreed with this
	     lg    992px   — comps used 64rem/1024px here; dropped
	     xl   1200px
	     xxl  1400px

	   Page measure is .container-xl (D6): 1140px from xl, 1320px from xxl.
	   The comps' 1340px --max is dropped. */

	/* --- Container measure — TRANSITIONAL, pending D6 ---------------------------
	   D6 makes .container-xl the page measure and drops 1340px. Completing that
	   is a markup change: .cst-page .wrap (cst-public.css:33) and .cst-hdr__in
	   (cst-header.css:33) would each have to become a .container-xl, which is a
	   restyle and therefore Phase 4 work.

	   This token keeps those two rules working at their current width so Phase 2
	   changes the token source and nothing else. Delete it when D6 lands. */
	/* Phase 4 */


	/* --- Feedback surfaces (D-none; Phase 3 Step 1) ----------------------------
	   Named so toast and modal chrome stops being invented per section. The
	   three feedback mechanisms the audit found (admin toast, company fade,
	   public modal) collapse to Tabler toast + modal in Phase 4. */
	--cst-toast-bg:            var(--cst-surface);   /* Toast body. Solid, not tinted — severity is carried by the icon and left border, not the whole surface. */
	--cst-toast-border:        var(--cst-border);    /* Toast outline, so it reads on a white page. */
	--cst-toast-accent-width:  3px;                  /* Left border that carries severity. */
	--cst-modal-backdrop:      rgb(var(--cst-shadow-rgb) / 50%);  /* Scrim behind a modal. Was Bootstrap's default plus a one-off .8 override in templates/header.cfm. */


/* =============================================================================
   CHART SERIES PALETTE (D22)

   For ApexCharts via Tabler's integration. Ordered: a chart with two series
   uses 1 and 2, and so on.

   HOW THESE WERE DERIVED
   Three brand colours are too light to read as a mark on a white card, so they
   were darkened along their own hue until they cleared 3:1 against #fff:
     --cst-terracotta     #ffb262 -> #dc7000
     --cst-eyebrow-green  #7fbe41 -> #689c35
     --cst-badge          #ffdf72 -> #af8700
   The rest are brand tokens unchanged.

   MEASURED SEPARATION (CIE dE76, higher is more distinguishable)
     first 4 series   dE >= 42.9   clearly distinct   <- D22's requirement
     first 5 series   dE >= 28.5   usable
     first 7 series   dE >= 22.2   usable
   Contrast on white ranges 3.30:1 (terracotta) to 9.21:1 (ink-soft); on the
   band surface #f2f2ec, 2.94:1 to 8.19:1.

   WHY SLOT 8 IS A NEUTRAL — a judgement call, flagged for review.
   The brand has four hue families (green, blue, orange, olive). Eight
   distinguishable hues are not available from it: every brand-derived
   candidate for an eighth slot came out below dE 20 against one of the first
   seven, the worst being --cst-gold vs --cst-terracotta-ink at dE 15.8, which
   are near-identical browns. Rather than ship a colour that reads as a
   duplicate, slot 8 is a neutral carrying the conventional "Other / remainder"
   meaning. It was a grey (#757575, 4.61:1 on white); the developer changed it
   to a light blue-grey (#c9d3e0) — deliberately recessive at ~1.5:1 on white,
   which is BELOW the 3:1 floor the other seven slots hold, so it should be used
   only for a de-emphasised remainder, never a series that must be read.

   A chart needing more than five distinct categories should change encoding —
   small multiples, or direct labelling — rather than lean on slots 6 to 8. */

	--cst-chart-1:  #006624;  /* = --cst-accent */
	--cst-chart-2:  #406bab;  /* = --cst-logo-blue */
	--cst-chart-3:  #dc7000;  /* --cst-terracotta, darkened to clear 3:1 on white */
	--cst-chart-4:  #7a5a12;  /* = --cst-gold */
	--cst-chart-5:  #689c35;  /* --cst-eyebrow-green, darkened to clear 3:1 */
	--cst-chart-6:  #34486a;  /* = --cst-ink-soft */
	--cst-chart-7:  #af8700;  /* --cst-badge, darkened to clear 3:1 */
	--cst-chart-8:  #c9d3e0;  /* Light blue-grey neutral for "Other / remainder" (developer's choice). Intentionally recessive: ~1.5:1 on white, below the palette's 3:1 series floor — see note above. */

	--cst-chart-grid:     var(--cst-border-subtle);  /* Gridlines. Must sit behind the data, never compete with it. */
	--cst-chart-axis:     var(--cst-border);         /* Axis lines and ticks. */
	--cst-chart-label:    var(--cst-muted);          /* Axis and legend text. */
	--cst-chart-tooltip-bg:      var(--cst-ink);     /* Tooltip surface — dark, so it reads over any series colour. */
	--cst-chart-tooltip-text:    var(--cst-surface); /* Tooltip text. */

	/* --- Course-action fills (Tier C) ------------------------------------------
	   The one place the button set is state-coded on purpose. A learner
	   scanning a list of course cards reads the action colour before the label,
	   so each course state gets its own hue — the exception the general
	   "buttons carry no state colour" rule needs, documented in
	   03-components.md and 04-patterns.md.

	   Every fill is dark enough that the WHITE label clears 4.5:1 on it, which
	   Tabler's stock success/warning/info do NOT (2.74 / 3.04 / 3.05). Ratios
	   in the comments are white-on-fill. Disabled states (Not Available, Not
	   Passed) are not here — they stay Tabler's grey/red disabled.

	   Hover is a darker shade of the same hue, so the affordance is unchanged. */
	--cst-course-start:        var(--cst-accent);        /* Start course — the brand "go" green. 7.18:1 */
	--cst-course-start-hover:  var(--cst-accent-hover);  /* 10.11:1 */
	--cst-course-resume:       #a05a00;  /* Resume — amber, "you are mid-way". 5.31:1 */
	--cst-course-resume-hover: #7a4300;  /* 7.98:1 */
	--cst-course-test:         #1a5fb4;  /* Start/Retake test — blue, "assessment". 6.29:1 */
	--cst-course-test-hover:   #144a8c;  /* 8.79:1 */
	--cst-course-eval:         #7a3fa0;  /* Complete evaluation — purple, "feedback". 6.89:1 */
	--cst-course-eval-hover:   #5f3080;  /* 9.45:1 */
	--cst-course-done:         #0f5c52;  /* Completed — teal, terminal and positive. 7.86:1 */
	--cst-course-done-hover:   #0a453d;  /* 10.87:1 */
	--cst-course-cert:         #6b5010;  /* Print/download certificate — gold, the reward. 7.55:1 */
	--cst-course-cert-hover:   #523d0c;  /* 10.34:1 */

}


/* =============================================================================
   DENSE TYPE SCALE (D15)

   Two density contexts, one token vocabulary. `:root` carries the comps' scale
   — 17px body, generous ramp — for public and Tier A reading pages. Adding
   `.cst-dense` to a container remaps THE SAME token names to a compact scale
   for company, admin and learner table views.

   A component therefore never asks which density it is in. It reads
   --cst-text-base and gets 17px on a marketing page and 14px in an admin
   table.

   RULES THIS SCALE OBEYS
     - Body stays 14px. --tblr-body-font-size is NOT changed; Tabler's own 14px
       already matches, so dense UI and Tabler agree by default.
     - h4 is the same size as body (14px) and is differentiated by WEIGHT and
       TRACKING, never by being smaller than the text it introduces. A heading
       smaller than its body copy was one of the audit's findings about
       Tabler's own scale (h3 16px, h4 14px, against comp body of 17px).
     - The caption step (11px) is the floor. Nothing in the UI goes below it.

   MAPPING — root step -> dense value, and what uses it
     caption  12px -> 11px   table meta, timestamps, helper text under a field
     2xs      12px -> 11px   micro labels
     xs       13px -> 12px   badges, pills, column labels
     sm       14px -> 13px   secondary text, table cell meta
     md       15px -> 14px   dense controls
     base     17px -> 14px   BODY, table cells, form inputs, buttons
     lg       19px -> 16px   h3, card titles
     xl       28px -> 20px   h2, section headings
     2xl      32px -> 24px   h1, page title
     3xl      44px -> 28px   the largest stat figure a dense view should use
   ============================================================================= */

.cst-dense {
	--cst-text-caption:  0.6875rem;  /* 11px — the dense floor. */
	--cst-text-2xs:      0.6875rem;  /* 11px */
	--cst-text-xs:       0.75rem;    /* 12px */
	--cst-text-sm:       0.8125rem;  /* 13px */
	--cst-text-md:       0.875rem;   /* 14px */
	--cst-text-base:     0.875rem;   /* 14px — body. Matches Tabler's own default. */
	--cst-text-lg:       1rem;       /* 16px — h3 */
	--cst-text-xl:       1.25rem;    /* 20px — h2 */
	--cst-text-2xl:      1.5rem;     /* 24px — h1 */
	--cst-text-3xl:      1.75rem;    /* 28px */

	/* Dense copy sits tighter, but not so tight that a wrapped table cell
	   collides with the row below. */
	--cst-leading-relaxed:  1.5;   /* was 1.6 */
	--cst-leading-normal:   1.45;  /* was 1.5 */

	/* h4 carries its rank through weight and tracking because it cannot do it
	   through size. Components read these rather than hardcoding. */
	--cst-h4-weight:    var(--cst-weight-bold);   /* 700 */
	--cst-h4-tracking:  var(--cst-tracking-wide); /* .04em */

	/* Dense UI steps down one spacing notch for the stack rhythm inside cards,
	   table cells and form rows. The scale itself is unchanged — only which
	   step the default rhythm points at. */
	--cst-stack-gap:  var(--cst-space-3);  /* 12px, against 16px at root. */

	/* Component metrics. --cst-row-action-size is deliberately NOT reduced: a
	   32px square is already at the lower bound of a comfortable pointer target
	   and shrinking it in the densest views is where it is needed most. */
	--cst-table-row-height:  var(--cst-space-7);  /* 32px */
	--cst-table-cell-pad-x:  var(--cst-space-3);  /* 12px */
}


/* =============================================================================
   5. TABLER BINDINGS

   The ONLY place in the codebase where a --tblr-* variable is assigned.
   Anything that needs to change Tabler's appearance changes it here.

   Tabler 1.0.0 scopes its own tokens under `:root, [data-bs-theme="light"]`.
   A bare `:root` loses to the attribute selector, so we declare into both.

   DELIBERATELY NOT SET
     --tblr-*-fg          Tabler uses these for foreground text on tinted
                          backgrounds. Overriding them previously produced
                          invisible text on same-colour buttons.
     --tblr-secondary     Grey returns to Tabler's secondary slot (D3).
     --tblr-success/-warning/-info/-danger
                          State colours use Tabler's defaults (D4).
     --tblr-body-font-size
                          Stays at Tabler's 14px. See the note in section 2.
     --tblr-border-radius*
                          Already identical to the comps. See section 4.
     --bs-*               Tabler 1.0.0 does not read Bootstrap-prefixed
                          variables (only --bs-position, an internal). Every
                          --bs-* assignment in the old include was inert.
                          See docs/decisions.md DF4.
   ============================================================================= */

:root,
[data-bs-theme="light"] {

	/* --- Primary = the accent green (D3) ------------------------------------ */
	--tblr-primary:      var(--cst-accent);       /* Buttons, active states, checked controls, focus. */
	--tblr-primary-rgb:  0, 102, 36;              /* Tuple for .bg-primary / .text-bg-primary rgba() use. Must track --cst-accent. */
	--tblr-primary-lt:   rgba(0, 102, 36, 0.1);   /* .bg-primary-lt tint badges. */

	/* --- Links ---------------------------------------------------------------
	   Tabler's `a` rule reads --tblr-link-color-rgb, which nothing overrode
	   before, so every link in the application rendered Tabler's default blue.
	   See docs/decisions.md DF5. */
	--tblr-link-color:        var(--cst-accent);        /* Link text. */
	--tblr-link-color-rgb:    0, 102, 36;               /* What Tabler's `a` rule actually reads. */
	--tblr-link-hover-color:  var(--cst-accent-hover);  /* Link hover. */

	/* --- Surfaces and text ---------------------------------------------------- */
	--tblr-body-bg:         var(--cst-page-bg);  /* Page background. White (D2). */
	--tblr-body-color:      var(--cst-ink);      /* Body text. Brand ink, was Tabler's #182433. */
	--tblr-body-color-rgb:  22, 38, 60;          /* Tuple. Must track --cst-ink. */
	--tblr-border-color:    var(--cst-border);   /* Card, table and control borders. */

	/* --- Typography ------------------------------------------------------------ */
	--tblr-font-sans-serif:  var(--cst-font-sans);  /* All UI text. */
	--tblr-font-monospace:   var(--cst-font-mono);  /* Code and identifiers. */

	/* --- Cards: flat with a border (D17) ---------------------------------------
	   Tabler ships a resting shadow on every card, which put one on all 354
	   back-office cards while the comps' cards are flat with a 1px border.
	   D17 resolves it in favour of flat, everywhere. Shadow is reserved for
	   floating things — see the elevation roles in section 4. */
	--tblr-card-box-shadow:    none;                          /* Flat (D17). */
	--tblr-card-border-color:  var(--cst-border);              /* Was Tabler's translucent cool grey; now the warm brand border. */
	--tblr-card-bg:            var(--cst-surface);             /* Explicit, so a card never inherits the page band. */

	/* --- Floating surfaces (D17) ----------------------------------------------
	   The other half of D17: things that DO float get the elevation roles. */
	--tblr-dropdown-box-shadow:  var(--cst-shadow-overlay);
	--tblr-modal-box-shadow:     var(--cst-shadow-modal);
	--tblr-toast-box-shadow:     var(--cst-shadow-toast);
	--tblr-backdrop-bg:          var(--cst-modal-backdrop);

	/* --- Badges ----------------------------------------------------------------
	   Tabler re-declares --tblr-badge-color inside the .badge rule itself, which
	   beats a :root value. The compatibility rule in section 6 is what actually
	   applies this. */
	--tblr-badge-color:  var(--cst-badge-text);  /* Text on solid badges. */

}


/* =============================================================================
   6. COMPATIBILITY RULES

   The two real rules the old include emitted, preserved so Step 2 changes the
   token source and nothing else. Both are component rules rather than tokens
   and should move to a component stylesheet in Phase 3/4.
   ============================================================================= */

/* Tabler sets no background on `body` — only on `.page`, which this application
   does not use. The page background therefore has to be painted explicitly or
   it falls through to the user-agent default. */
body,
.page,
.page-wrapper,
.page-body {
	background-color: var(--cst-page-bg);
}

/* Tabler declares --tblr-badge-color inside .badge, so the :root binding above
   cannot reach it. Setting `color` directly is the only way to hold one badge
   text colour. Whether a single colour is right at all is a Phase 3 question —
   see docs/decisions.md DF6. */
.badge {
	color: var(--cst-badge-text);
}

/* --- DataTables' own variables (D30) ---------------------------------------
   The Bootstrap 5 integration build declares a small `--dt-*` set in its own
   `:root`, and `--dt-row-selected` ships as Bootstrap blue. It is consumed as
   `rgb(var(--dt-row-selected))`, so these must be COMMA-SEPARATED TRIPLES, not
   hex — which is why they restate a value instead of pointing at a token.

   KEEP IN STEP BY HAND with the tokens named in each comment. This is the same
   constraint, and the same hazard, as templates/_status_colours.cfm: nothing
   checks that these agree.

   Only the selection pair is bound. --dt-row-stripe and --dt-row-hover are
   left at DataTables' neutral black-at-low-alpha: striping is off (D-spec,
   03-components.md) and hover is handled by .cst-table. */
:root {
	--dt-row-selected:       232, 243, 224;  /* --cst-accent-pale  #e8f3e0 */
	--dt-row-selected-text:   22,  38,  60;  /* --cst-ink          #16263c */
	--dt-row-selected-link:   22,  38,  60;  /* --cst-ink          #16263c */
}

/* --- The back-office navbar's Tabler variables (D35) -----------------------
   `.cst-navbar` in cst-components.css §11 paints the bar; these are the
   Tabler variables the bar's CONTENTS inherit from, and they have to be here
   because section 5 owns every --tblr-* assignment.

   Binding the variables rather than out-specifying `.nav-link` is what makes
   the avatar dropdown work. Its toggle carries `.text-reset`, i.e.
   `color: inherit`, so it takes whatever --tblr-navbar-color resolves to and
   no rule targeting `.nav-link` reaches it. Left unbound it inherited
   Tabler's default #6c7a91 — 4.35:1 on white, under AA, and the exact value
   03-components.md rejected for .btn-secondary. */
.cst-navbar {
	--tblr-navbar-color:               var(--cst-ink-soft);
	--tblr-navbar-hover-color:         var(--cst-accent);
	--tblr-navbar-active-color:        var(--cst-accent);
	--tblr-navbar-disabled-color:      var(--cst-muted);
	--tblr-navbar-brand-color:         var(--cst-ink);
	--tblr-navbar-brand-hover-color:   var(--cst-ink);
	--tblr-navbar-toggler-border-color: var(--cst-border);
}

/* --- .btn-secondary is outlined -------------------------------------------
   03-components.md's button table: "surface fill, ink label, secondary
   border", and `.btn-outline-secondary` is retained as an ALIAS of it rather
   than a second variant. The guide settled this in Phase 3 but nothing
   implemented it, so both classes kept rendering Tabler's stock treatment —
   a filled `--tblr-secondary` (#6c7a91) with white text. Caught on the first
   migrated page, where the roster's Search button came out filled grey.

   Why outlined and not the filled grey components.md first proposed: #6c7a91
   fails AA against either label — white 4.35:1, ink 3.51:1. Outlined passes
   cleanly: ink label 15.25:1, and the border 4.35:1 against the 3:1
   threshold WCAG 1.4.11 sets for a UI component boundary.

   Done by rebinding Tabler's own button variables rather than overriding
   `background`/`color`/`border` directly, so every size, focus ring, disabled
   state and `.btn-icon` case Tabler derives from them keeps working. Hover
   darkens the border and lifts the fill to the band, which is a real state
   change without moving the label's contrast. */
.btn-secondary,
.btn-outline-secondary {
	--tblr-btn-color:                var(--cst-ink);
	--tblr-btn-bg:                   var(--cst-surface);
	--tblr-btn-border-color:         var(--tblr-secondary);

	--tblr-btn-hover-color:          var(--cst-ink);
	--tblr-btn-hover-bg:             var(--cst-band);
	--tblr-btn-hover-border-color:   var(--tblr-secondary-darken);

	--tblr-btn-active-color:         var(--cst-ink);
	--tblr-btn-active-bg:            var(--cst-band);
	--tblr-btn-active-border-color:  var(--tblr-secondary-darken);

	--tblr-btn-disabled-color:       var(--cst-ink);
	--tblr-btn-disabled-bg:          var(--cst-surface);
	--tblr-btn-disabled-border-color: var(--tblr-secondary);
}
