/*
 * moshtix-theme.css — the Streetix design system as a Bootstrap 5.3 theme.
 *
 * Every colour, typeface, size, radius and shadow on the site starts here, in
 * both modes: dark is the designed default, light is the alternate, switched
 * by <html data-bs-theme="dark|light">.
 *
 * Design source: Figma "Streetix 2.0", frame 623:5
 *   https://www.figma.com/design/TYnBEHfk4lvyACGToYIQQM/Streetix-2.0?node-id=623-5&m=dev
 * Targets the vendored Bootstrap v5.3.8. Must load after bootstrap.min.css
 * and before the tenant stylesheet — _Layout.cshtml owns that order.
 *
 * The full token reference (every --mx-* variable, values, what to use each
 * one for) lives in client-app/README.md under "Theming". This header only
 * covers what you need to edit this file safely.
 *
 * HOW THE FILE IS ORGANISED — four sections, top to bottom:
 *
 *   1. PRIMITIVES        the raw palette (--mx-neutral-800, --mx-teal-500).
 *                        Never use these in a component or page — that's what
 *                        layer 2 is for.
 *   2. SEMANTIC TOKENS   what things mean (--mx-accent, --mx-surface-default,
 *                        --mx-text-secondary). The ONLY layer tenants may
 *                        override.
 *   3. BOOTSTRAP BRIDGE  layer 2 assigned onto Bootstrap's own --bs-*
 *                        variables, so stock Bootstrap components pick up the
 *                        theme.
 *   4. COMPONENT BRIDGE  Bootstrap's per-component variables (--bs-btn-*,
 *                        --bs-card-*, …). Variables only — no property
 *                        redeclarations, no !important. That discipline is
 *                        why one token change rethemes every button state,
 *                        focus ring and nav item without specificity fights.
 *
 * CHANGING A COLOUR (yours or a tenant's): override the -rgb TRIPLET, not the
 * hex, and only in layer 2. In a tenant stylesheet (loads after this file):
 *
 *   :root,
 *   [data-bs-theme='dark'] {
 *     --mx-accent-rgb: 255, 106, 0;
 *   }
 *
 * Why the triplet: Bootstrap's opacity utilities (.bg-opacity-*, .text-*,
 * focus rings, alert tints) read rgba(var(--bs-primary-rgb), …). Override
 * only the hex and those utilities keep painting the old colour while solid
 * fills change — a split-brain theme that is miserable to debug. The hex
 * forms are composed from the triplets, so overriding the triplet updates
 * both. And never override --bs-* directly: it's derived here, and a tenant
 * that sets it is silently detached from future theme changes.
 *
 * PROVENANCE MARKERS used throughout this file:
 *   [DOC]      straight from the Figma frame or its bound variables.
 *   [INFERRED] not in the design — chosen here, wants designer sign-off.
 *              (Mostly light mode: the Figma light column only defines the
 *              three backgrounds; the rest would have been white-on-white.)
 *   [DERIVED]  computed from a [DOC] value (e.g. tints via color-mix).
 *
 * Browser note: color-mix() needs Chrome 111+ / Safari 16.2+ / Firefox 113+;
 * every use here has a static fallback declared immediately before it.
 */

/* ===========================================================================
 * 1. PRIMITIVES — Streetix brand palette
 * ---------------------------------------------------------------------------
 * [DOC] every value. Defined as RGB triplets; the hex form is composed from
 * the triplet so the two can never drift apart. See the override contract.
 * ======================================================================== */
:root {
  /* Neutral — 950 (darkest) to 0 (white) */
  --mx-neutral-950-rgb: 16, 11, 13;
  --mx-neutral-900-rgb: 19, 19, 26;
  --mx-neutral-850-rgb: 28, 28, 38;
  --mx-neutral-800-rgb: 37, 37, 53;
  --mx-neutral-700-rgb: 46, 46, 64;
  --mx-neutral-600-rgb: 61, 61, 82;
  --mx-neutral-500-rgb: 90, 90, 117;
  --mx-neutral-400-rgb: 122, 122, 152;
  --mx-neutral-300-rgb: 168, 168, 192;
  --mx-neutral-200-rgb: 208, 208, 224;
  --mx-neutral-100-rgb: 238, 238, 245;
  --mx-neutral-0-rgb: 255, 255, 255;

  --mx-neutral-950: rgb(var(--mx-neutral-950-rgb)); /* #100B0D */
  --mx-neutral-900: rgb(var(--mx-neutral-900-rgb)); /* #13131A */
  --mx-neutral-850: rgb(var(--mx-neutral-850-rgb)); /* #1C1C26 */
  --mx-neutral-800: rgb(var(--mx-neutral-800-rgb)); /* #252535 */
  --mx-neutral-700: rgb(var(--mx-neutral-700-rgb)); /* #2E2E40 */
  --mx-neutral-600: rgb(var(--mx-neutral-600-rgb)); /* #3D3D52 */
  --mx-neutral-500: rgb(var(--mx-neutral-500-rgb)); /* #5A5A75 */
  --mx-neutral-400: rgb(var(--mx-neutral-400-rgb)); /* #7A7A98 */
  --mx-neutral-300: rgb(var(--mx-neutral-300-rgb)); /* #A8A8C0 */
  --mx-neutral-200: rgb(var(--mx-neutral-200-rgb)); /* #D0D0E0 */
  --mx-neutral-100: rgb(var(--mx-neutral-100-rgb)); /* #EEEEF5 */
  --mx-neutral-0: rgb(var(--mx-neutral-0-rgb)); /*   #FFFFFF */

  /* Teal — accent */
  --mx-teal-600-rgb: 0, 204, 204;
  --mx-teal-500-rgb: 0, 225, 255;
  --mx-teal-400-rgb: 53, 255, 252;
  --mx-teal-300-rgb: 112, 248, 255;
  --mx-teal-100-rgb: 0, 42, 43;

  --mx-teal-600: rgb(var(--mx-teal-600-rgb)); /* #00CCCC */
  --mx-teal-500: rgb(var(--mx-teal-500-rgb)); /* #00E1FF */
  --mx-teal-400: rgb(var(--mx-teal-400-rgb)); /* #35FFFC */
  --mx-teal-300: rgb(var(--mx-teal-300-rgb)); /* #70F8FF */
  --mx-teal-100: rgb(var(--mx-teal-100-rgb)); /* #002A2B */

  /* Pink — secondary */
  --mx-pink-500-rgb: 255, 0, 242;
  --mx-pink-400-rgb: 249, 121, 223;
  --mx-pink-100-rgb: 34, 10, 27;

  --mx-pink-500: rgb(var(--mx-pink-500-rgb)); /* #FF00F2 */
  --mx-pink-400: rgb(var(--mx-pink-400-rgb)); /* #F979DF */
  --mx-pink-100: rgb(var(--mx-pink-100-rgb)); /* #220A1B */

  /* Status */
  --mx-status-green-rgb: 34, 197, 94;
  --mx-status-red-rgb: 239, 68, 68;
  --mx-status-yellow-rgb: 234, 179, 8;
  --mx-status-cyan-rgb: 6, 182, 212;

  --mx-status-green: rgb(var(--mx-status-green-rgb)); /*  #22C55E */
  --mx-status-red: rgb(var(--mx-status-red-rgb)); /*      #EF4444 */
  --mx-status-yellow: rgb(var(--mx-status-yellow-rgb)); /* #EAB308 */
  --mx-status-cyan: rgb(var(--mx-status-cyan-rgb)); /*    #06B6D4 */
}

/* ===========================================================================
 * 2. SEMANTIC TOKENS  >>> TENANT OVERRIDE SURFACE <<<
 * ======================================================================== */

/* ---- Dark mode — the designed default. [DOC] every value. ---------------
 * Also applied to :root so the theme still renders if data-bs-theme is
 * missing from <html>; the attribute selector wins when it is present. */
:root,
[data-bs-theme='dark'] {
  color-scheme: dark;

  /* Backgrounds — page-level fills */
  --mx-bg-base-rgb: var(--mx-neutral-950-rgb);
  --mx-bg-subtle-rgb: var(--mx-neutral-900-rgb);
  --mx-bg-muted-rgb: var(--mx-neutral-850-rgb);

  /* Surfaces — cards and panels; each step lifts toward the foreground */
  --mx-surface-default-rgb: var(--mx-neutral-800-rgb);
  --mx-surface-elevated-rgb: var(--mx-neutral-700-rgb);
  --mx-surface-overlay-rgb: var(--mx-neutral-600-rgb);

  /* Borders — ascending emphasis */
  --mx-border-subtle-rgb: var(--mx-neutral-700-rgb);
  --mx-border-default-rgb: var(--mx-neutral-600-rgb);
  --mx-border-strong-rgb: var(--mx-neutral-500-rgb);

  /* Text — descending emphasis */
  --mx-text-primary-rgb: var(--mx-neutral-0-rgb);
  --mx-text-secondary-rgb: var(--mx-neutral-300-rgb);
  --mx-text-tertiary-rgb: var(--mx-neutral-400-rgb);
  --mx-text-disabled-rgb: var(--mx-neutral-500-rgb);
  /* Text placed ON accent/secondary fills. Both brand colours are bright in
     either mode, so this stays dark in light mode too — not a copy/paste slip. */
  --mx-text-inverse-rgb: var(--mx-neutral-950-rgb);

  /* Accent — teal */
  --mx-accent-rgb: var(--mx-teal-500-rgb);
  --mx-accent-hover-rgb: var(--mx-teal-400-rgb);
  --mx-accent-muted-rgb: var(--mx-teal-100-rgb);
  --mx-accent-strong-rgb: var(--mx-teal-600-rgb);
  --mx-accent-on-rgb: var(--mx-neutral-0-rgb);

  /* Secondary — pink */
  --mx-secondary-rgb: var(--mx-pink-500-rgb);
  --mx-secondary-hover-rgb: var(--mx-pink-400-rgb);
  --mx-secondary-muted-rgb: var(--mx-pink-100-rgb);

  /* Status */
  --mx-success-rgb: var(--mx-status-green-rgb);
  --mx-error-rgb: var(--mx-status-red-rgb);
  --mx-warning-rgb: var(--mx-status-yellow-rgb);
  --mx-info-rgb: var(--mx-status-cyan-rgb);
}

/* ---- Light mode ---------------------------------------------------------
 * [DOC]      bg-base / bg-subtle / bg-muted, text-inverse, and every brand
 *            and status colour (all mode-invariant by design).
 * [INFERRED] everything else. See PROVENANCE. */
[data-bs-theme='light'] {
  color-scheme: light;

  /* [DOC] The design mirrors the Neutral ramp: 950->0, 900->100, 850->200. */
  --mx-bg-base-rgb: var(--mx-neutral-0-rgb);
  --mx-bg-subtle-rgb: var(--mx-neutral-100-rgb);
  --mx-bg-muted-rgb: var(--mx-neutral-200-rgb);

  /* [INFERRED] Light does NOT mirror dark here, deliberately. The page is
     #FFFFFF ([DOC]), so surfaces cannot lift toward white — they separate by
     tinting away from it, and floating overlays go back to white and rely on
     their shadow. That is the standard light-UI model: elevation is shadow,
     not lightness.
     Steps are sized to match the dark ladder's perceived separation
     (card->header 1.14x, header->overlay 1.28x). The earlier values spanned
     only 3% end to end, which made cards, headers and dropdowns
     indistinguishable in light mode. */
  --mx-surface-default-rgb: 240, 241, 249;
  --mx-surface-elevated-rgb: 224, 227, 240;
  --mx-surface-overlay-rgb: var(--mx-neutral-0-rgb);

  /* [INFERRED] Mirrors the dark ordering: subtle -> strong gets darker. */
  --mx-border-subtle-rgb: var(--mx-neutral-200-rgb);
  --mx-border-default-rgb: var(--mx-neutral-300-rgb);
  --mx-border-strong-rgb: var(--mx-neutral-400-rgb);

  /* [INFERRED] Contrast on #FFFFFF: primary ~19:1, secondary ~12.7:1,
     tertiary ~6.4:1 — all clear of WCAG AA. */
  --mx-text-primary-rgb: var(--mx-neutral-950-rgb);
  --mx-text-secondary-rgb: var(--mx-neutral-600-rgb);
  --mx-text-tertiary-rgb: var(--mx-neutral-500-rgb);
  --mx-text-disabled-rgb: var(--mx-neutral-300-rgb);
  --mx-text-inverse-rgb: var(--mx-neutral-950-rgb); /* [DOC] */

  /* [INFERRED] The muted tokens are the exception to mode-invariance. Teal
     100 (#002A2B) and Pink 100 (#220A1B) are near-black tints meant to sit on
     a dark page; as ghost-button fills on white they read as solid dark chips.
     These are the same hues lightened instead. */
  --mx-accent-muted-rgb: 224, 251, 255; /* #E0FBFF */
  --mx-secondary-muted-rgb: 255, 229, 253; /* #FFE5FD */
}

/* ---- Composed hex forms ------------------------------------------------
 * Applied to every theme root so both modes resolve. Tenants override the
 * triplets above; these follow automatically. */
:root,
[data-bs-theme='dark'],
[data-bs-theme='light'] {
  --mx-bg-base: rgb(var(--mx-bg-base-rgb));
  --mx-bg-subtle: rgb(var(--mx-bg-subtle-rgb));
  --mx-bg-muted: rgb(var(--mx-bg-muted-rgb));

  --mx-bg-content: rgba(var(--mx-bg-base-rgb), 0.88);

  --mx-surface-default: rgb(var(--mx-surface-default-rgb));
  --mx-surface-elevated: rgb(var(--mx-surface-elevated-rgb));
  --mx-surface-overlay: rgb(var(--mx-surface-overlay-rgb));

  --mx-border-subtle: rgb(var(--mx-border-subtle-rgb));
  --mx-border-default: rgb(var(--mx-border-default-rgb));
  --mx-border-strong: rgb(var(--mx-border-strong-rgb));

  --mx-text-primary: rgb(var(--mx-text-primary-rgb));
  --mx-text-secondary: rgb(var(--mx-text-secondary-rgb));
  --mx-text-tertiary: rgb(var(--mx-text-tertiary-rgb));
  --mx-text-disabled: rgb(var(--mx-text-disabled-rgb));
  --mx-text-inverse: rgb(var(--mx-text-inverse-rgb));

  --mx-accent: rgb(var(--mx-accent-rgb));
  --mx-accent-hover: rgb(var(--mx-accent-hover-rgb));
  --mx-accent-muted: rgb(var(--mx-accent-muted-rgb));
  --mx-accent-strong: rgb(var(--mx-accent-strong-rgb));
  --mx-accent-on: rgb(var(--mx-accent-on-rgb));

  --mx-secondary: rgb(var(--mx-secondary-rgb));
  --mx-secondary-hover: rgb(var(--mx-secondary-hover-rgb));
  --mx-secondary-muted: rgb(var(--mx-secondary-muted-rgb));

  --mx-success: rgb(var(--mx-success-rgb));
  --mx-error: rgb(var(--mx-error-rgb));
  --mx-warning: rgb(var(--mx-warning-rgb));
  --mx-info: rgb(var(--mx-info-rgb));

  /* Links default to the accent, but are their own token: brands routinely use
     a different colour for inline links than for primary buttons, and without
     this a tenant would have to reach past the --mx-* contract into --bs-*. */
  --mx-link-rgb: var(--mx-accent-rgb);
  --mx-link-hover-rgb: var(--mx-accent-hover-rgb);
  --mx-link: rgb(var(--mx-link-rgb));
  --mx-link-hover: rgb(var(--mx-link-hover-rgb));
  --mx-text-heading-rgb: var(--mx-text-primary-rgb);
  --mx-text-heading: rgb(var(--mx-text-heading-rgb));

  /* Field fills (inputs, selects, editors) default to the page background,
     but are their own token for the same reason as links above: Bootstrap
     hard-wires .form-control to --bs-body-bg, so without this slot a tenant
     that retints the page is forced to accept retinted fields too. */
  --mx-field-bg-rgb: var(--mx-bg-base-rgb);
  --mx-field-bg: rgb(var(--mx-field-bg-rgb));

  /* Shape and elevation. Not in the design doc — [INFERRED] from the rounded
     corners visible in the button and input mockups. */
  --mx-radius-sm: 0.375rem;
  --mx-radius: 0.5rem;
  --mx-radius-lg: 0.75rem;
  --mx-radius-pill: 50rem;

  --mx-shadow-overlay: 0 12px 32px rgba(0, 0, 0, 0.5);
  --mx-focus-ring-width: 3px;
  --mx-focus-ring-opacity: 0.25;
}

/* ===========================================================================
 * 3. BOOTSTRAP GLOBAL BRIDGE
 * ---------------------------------------------------------------------------
 * Bootstrap 5.3 resolves everything through --bs-*. Mapping the semantic
 * tokens here is what makes the design doc's step 2 true — "all Bootstrap
 * components inherit the Streetix theme automatically" — which is NOT the
 * case from data-bs-theme="dark" alone.
 *
 * Both the colour and its -rgb triplet are set for every theme colour.
 * Bootstrap's utilities (.bg-*, .text-*, .border-*, .bg-opacity-*) resolve
 * through the triplet; miss it and those utilities keep painting Bootstrap
 * blue while solid fills turn teal.
 * ======================================================================== */
:root,
[data-bs-theme='dark'],
[data-bs-theme='light'] {
  /* -- Body and surfaces -- */
  --bs-body-bg: var(--mx-bg-base);
  --bs-body-bg-rgb: var(--mx-bg-base-rgb);
  --bs-body-color: var(--mx-text-primary);
  --bs-body-color-rgb: var(--mx-text-primary-rgb);

  --bs-emphasis-color: var(--mx-text-primary);
  --bs-emphasis-color-rgb: var(--mx-text-primary-rgb);
  --bs-heading-color: var(--mx-text-heading);

  --bs-secondary-color: var(--mx-text-secondary);
  --bs-secondary-color-rgb: var(--mx-text-secondary-rgb);
  --bs-secondary-bg: var(--mx-bg-subtle);
  --bs-secondary-bg-rgb: var(--mx-bg-subtle-rgb);

  --bs-tertiary-color: var(--mx-text-tertiary);
  --bs-tertiary-color-rgb: var(--mx-text-tertiary-rgb);
  --bs-tertiary-bg: var(--mx-bg-muted);
  --bs-tertiary-bg-rgb: var(--mx-bg-muted-rgb);

  /* -- Borders and shape -- */
  --bs-border-color: var(--mx-border-default);
  --bs-border-color-translucent: var(--mx-border-subtle);
  --bs-border-width: 1px;
  --bs-border-radius: var(--mx-radius);
  --bs-border-radius-sm: var(--mx-radius-sm);
  --bs-border-radius-lg: var(--mx-radius-lg);
  --bs-border-radius-xl: var(--mx-radius-lg);
  --bs-border-radius-pill: var(--mx-radius-pill);

  /* -- Theme colours --
     Bootstrap's `primary` is the Streetix accent; `secondary` is the Streetix
     pink. See the naming note above .btn-outline-secondary in section 6. */
  --bs-primary: var(--mx-accent);
  --bs-primary-rgb: var(--mx-accent-rgb);
  --bs-secondary: var(--mx-secondary);
  --bs-secondary-rgb: var(--mx-secondary-rgb);
  --bs-success: var(--mx-success);
  --bs-success-rgb: var(--mx-success-rgb);
  --bs-danger: var(--mx-error);
  --bs-danger-rgb: var(--mx-error-rgb);
  --bs-warning: var(--mx-warning);
  --bs-warning-rgb: var(--mx-warning-rgb);
  --bs-info: var(--mx-info);
  --bs-info-rgb: var(--mx-info-rgb);
  --bs-light: var(--mx-neutral-100);
  --bs-light-rgb: var(--mx-neutral-100-rgb);
  --bs-dark: var(--mx-neutral-950);
  --bs-dark-rgb: var(--mx-neutral-950-rgb);

  /* -- 5.3 subtle/emphasis triads --
     Used by alerts, .bg-*-subtle, .text-*-emphasis and list groups.
     [DOC] for accent and secondary (the design defines muted tints);
     [DERIVED] for status, mixed against the page background. */
  --bs-primary-bg-subtle: var(--mx-accent-muted);
  --bs-primary-border-subtle: var(--mx-accent-strong);
  --bs-primary-text-emphasis: var(--mx-accent-hover);

  --bs-secondary-bg-subtle: var(--mx-secondary-muted);
  --bs-secondary-border-subtle: var(--mx-secondary);
  --bs-secondary-text-emphasis: var(--mx-secondary-hover);

  --bs-success-bg-subtle: rgba(var(--mx-success-rgb), 0.15);
  --bs-success-bg-subtle: color-mix(in srgb, var(--mx-success) 15%, var(--mx-bg-base));
  --bs-success-border-subtle: rgba(var(--mx-success-rgb), 0.4);
  --bs-success-text-emphasis: var(--mx-success);

  --bs-danger-bg-subtle: rgba(var(--mx-error-rgb), 0.15);
  --bs-danger-bg-subtle: color-mix(in srgb, var(--mx-error) 15%, var(--mx-bg-base));
  --bs-danger-border-subtle: rgba(var(--mx-error-rgb), 0.4);
  --bs-danger-text-emphasis: var(--mx-error);

  --bs-warning-bg-subtle: rgba(var(--mx-warning-rgb), 0.15);
  --bs-warning-bg-subtle: color-mix(in srgb, var(--mx-warning) 15%, var(--mx-bg-base));
  --bs-warning-border-subtle: rgba(var(--mx-warning-rgb), 0.4);
  --bs-warning-text-emphasis: var(--mx-warning);

  --bs-info-bg-subtle: rgba(var(--mx-info-rgb), 0.15);
  --bs-info-bg-subtle: color-mix(in srgb, var(--mx-info) 15%, var(--mx-bg-base));
  --bs-info-border-subtle: rgba(var(--mx-info-rgb), 0.4);
  --bs-info-text-emphasis: var(--mx-info);

  /* -- Links -- */
  --bs-link-color: var(--mx-link);
  --bs-link-color-rgb: var(--mx-link-rgb);
  --bs-link-hover-color: var(--mx-link-hover);
  --bs-link-hover-color-rgb: var(--mx-link-hover-rgb);

  /* -- Focus ring -- */
  --bs-focus-ring-width: var(--mx-focus-ring-width);
  --bs-focus-ring-opacity: var(--mx-focus-ring-opacity);
  --bs-focus-ring-color: rgba(var(--mx-accent-rgb), var(--mx-focus-ring-opacity));

  /* -- Form fields -- */
  /* Checkboxes/radios read this variable natively; text fields don't have one
     (Bootstrap hardcodes --bs-body-bg on the element), so those get the token
     via a declaration in section 5's form rules. */
  --bs-form-check-bg: var(--mx-field-bg);

  /* -- Form validation (these ARE variables in 5.3) -- */
  --bs-form-valid-color: var(--mx-success);
  --bs-form-valid-border-color: var(--mx-success);
  --bs-form-invalid-color: var(--mx-error);
  --bs-form-invalid-border-color: var(--mx-error);

  /* -- Misc -- */
  --bs-code-color: var(--mx-secondary-hover);
  --bs-highlight-bg: var(--mx-accent-muted);
  --bs-highlight-color: var(--mx-text-primary);

  /* -- Typography -- */
  --bs-font-sans-serif: var(--mx-font-sans);
  --bs-body-font-family: var(--mx-font-sans);
  --bs-body-font-size: var(--mx-font-size-body-m);
  --bs-body-font-weight: var(--mx-weight-body);
  /* MUST stay unitless. line-height inherits as a computed value, so a length
     here (1.5rem) would pin every descendant to 24px regardless of its own
     font-size — an h4 would get 24px leading at 20px type. The unitless ratio
     re-resolves per element. 1.5 === --mx-line-height-body-m / --mx-font-size-body-m;
     CSS cannot divide two lengths portably, hence the literal. */
  --bs-body-line-height: 1.5;
}

/* ===========================================================================
 * 4. TYPOGRAPHY
 * ---------------------------------------------------------------------------
 * Sizes, line-heights and tracking come from the bound Figma typography
 * variables, which carry metrics the visible table omits (Display XL is
 * 72/80/-2, not just "72").
 *
 * TYPEFACE: the doc's prose says Inter and links Google Fonts, but every bound
 * variable resolves to Font(family: "Satoshi", weight: 500). The stack below
 * resolves that at runtime — Satoshi where available, Inter carrying the
 * design today, system sans as the floor. Near-identical metrics, so the
 * fallback does not reflow.
 *
 * Satoshi is self-hosted as a variable font (satoshi.css +
 * Content/fonts/satoshi/, full 300–900 axis); Inter still comes from Google
 * Fonts. Both are <link>ed in _Layout.cshtml's head — @import is deliberately
 * avoided, it serialises font loading behind this stylesheet's own download.
 *
 * WEIGHTS: every bound variable is weight 500 (Satoshi Medium), which is what
 * is applied. The visible table instead labels styles Bold/SemiBold/Regular.
 * If the table is authoritative, set --mx-weight-display: 700 and
 * --mx-weight-heading: 600 — that is the entire change; the variable font
 * renders any weight in 300–900 for real (the old CDN link served only the
 * 500 face, so anything bolder was browser-synthesised).
 * ======================================================================== */
:root {
  --mx-font-sans: 'Satoshi', 'Inter', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

  /* Headings default to the body face, but are their own token — a display face
     paired with a neutral body face is the commonest typographic identity
     there is, and with a single font token it was not expressible at all. */
  --mx-font-heading: var(--mx-font-sans);

  --mx-weight-display: 500;
  --mx-weight-heading: 500;
  --mx-weight-body: 500;

  /* -- Type scale primitives --
   * Every size, line-height and tracking value in the design is a whole
   * multiple of one of these three units, so the scale is expressed as
   * multiplications rather than 33 unrelated literals. Retuning the scale is
   * a change here, not an audit of every rule.
   *
   *   --mx-font-size-base  16px. Sizes run 0.6875x (11px) to 4.5x (72px).
   *   --mx-baseline-unit    4px. Every line-height in the design divides by 4,
   *                         so the scale sits on a 4px baseline grid — a real
   *                         property of the design, not a convention imposed here.
   *   --mx-tracking-unit  0.1px. The smallest step used (Label, +0.1px); every
   *                         other value is an integer multiple, including the
   *                         -0.3px on Heading L that rules out a 0.5px unit. */
  --mx-font-size-base: 1rem;
  --mx-baseline-unit: 0.25rem;
  --mx-tracking-unit: 0.1px;

  /* -- Derived scale — one token per style per axis -- */

  /* Display XL — 72 / 80 / -2 */
  --mx-font-size-display-xl: calc(var(--mx-font-size-base) * 4.5);
  --mx-line-height-display-xl: calc(var(--mx-baseline-unit) * 20);
  --mx-tracking-display-xl: calc(var(--mx-tracking-unit) * -20);

  /* Display L — 56 / 64 / -1.5 */
  --mx-font-size-display-l: calc(var(--mx-font-size-base) * 3.5);
  --mx-line-height-display-l: calc(var(--mx-baseline-unit) * 16);
  --mx-tracking-display-l: calc(var(--mx-tracking-unit) * -15);

  /* Display M — 40 / 48 / -1 */
  --mx-font-size-display-m: calc(var(--mx-font-size-base) * 2.5);
  --mx-line-height-display-m: calc(var(--mx-baseline-unit) * 12);
  --mx-tracking-display-m: calc(var(--mx-tracking-unit) * -10);

  /* Heading XL (h1) — 32 / 40 / -0.5 */
  --mx-font-size-heading-xl: calc(var(--mx-font-size-base) * 2);
  --mx-line-height-heading-xl: calc(var(--mx-baseline-unit) * 10);
  --mx-tracking-heading-xl: calc(var(--mx-tracking-unit) * -5);

  /* Heading L (h2) — 24 / 32 / -0.3 */
  --mx-font-size-heading-l: calc(var(--mx-font-size-base) * 1.5);
  --mx-line-height-heading-l: calc(var(--mx-baseline-unit) * 8);
  --mx-tracking-heading-l: calc(var(--mx-tracking-unit) * -3);

  /* Heading M (h3) — 20 / 28 / 0 */
  --mx-font-size-heading-m: calc(var(--mx-font-size-base) * 1.25);
  --mx-line-height-heading-m: calc(var(--mx-baseline-unit) * 7);
  --mx-tracking-heading-m: calc(var(--mx-tracking-unit) * 0);

  /* Body L (p.lead) — 18 / 28 / 0 */
  --mx-font-size-body-l: calc(var(--mx-font-size-base) * 1.125);
  --mx-line-height-body-l: calc(var(--mx-baseline-unit) * 7);
  --mx-tracking-body-l: calc(var(--mx-tracking-unit) * 0);

  /* Body M (p) — 16 / 24 / 0 — the base size, hence the 1x multiplier */
  --mx-font-size-body-m: calc(var(--mx-font-size-base) * 1);
  --mx-line-height-body-m: calc(var(--mx-baseline-unit) * 6);
  --mx-tracking-body-m: calc(var(--mx-tracking-unit) * 0);

  /* Body S (small) — 14 / 20 / 0 */
  --mx-font-size-body-s: calc(var(--mx-font-size-base) * 0.875);
  --mx-line-height-body-s: calc(var(--mx-baseline-unit) * 5);
  --mx-tracking-body-s: calc(var(--mx-tracking-unit) * 0);

  /* Label — 14 / 20 / +0.1 — Body S metrics, tracked out by one unit */
  --mx-font-size-label: calc(var(--mx-font-size-base) * 0.875);
  --mx-line-height-label: calc(var(--mx-baseline-unit) * 5);
  --mx-tracking-label: calc(var(--mx-tracking-unit) * 1);

  /* Overline — 11 / 16 / +1.5 */
  --mx-font-size-overline: calc(var(--mx-font-size-base) * 0.6875);
  --mx-line-height-overline: calc(var(--mx-baseline-unit) * 4);
  --mx-tracking-overline: calc(var(--mx-tracking-unit) * 15);
}

/* ---- Page backdrop ------------------------------------------------------
 * One image for both modes. Tenants retheme by overriding the token — or set
 * it to `none` to drop the image — rather than restating the body rule; and
 * because the tenant sheet loads last, a tenant's own `body { background-image }`
 * still wins outright. Remote URL (demo asset), so there is no .csproj entry
 * to keep in sync. */
:root {
  --mx-bg-image: url('https://moshtix.com.au/directory/uploads/images/moshtix_streetix_demo_background.jpg');
}

body {
  /* Bootstrap already applies --bs-body-* to body; these are belt-and-braces
     for pages that reset it, plus the smoothing the faces expect. Satoshi and
     Inter both look heavy at display sizes without antialiasing hinted on. */
  background-color: var(--bs-body-bg);
  /* Layered over the base colour: if the image 404s or a tenant sets the token
     to `none`, the themed background-color still shows. */
  background-image: var(--mx-bg-image, none);
  background-repeat: no-repeat;
  background-position: center top;
  background-size: cover;
  background-attachment: fixed;
  color: var(--bs-body-color);
  font-family: var(--bs-body-font-family);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Bootstrap sizes h1-h6 with Sass, not variables, so these are real
   declarations rather than bridge entries. */
.display-xl,
.display-l,
.display-m {
  font-family: var(--mx-font-heading);
  font-weight: var(--mx-weight-display);
  /* Same token as h1-h6 — these ARE headings, and previously used
     --mx-text-primary, so a heading override silently skipped them. */
  color: var(--mx-text-heading);
  margin-bottom: calc(var(--mx-baseline-unit) * 4);
}

.display-xl {
  font-size: var(--mx-font-size-display-xl);
  line-height: var(--mx-line-height-display-xl);
  letter-spacing: var(--mx-tracking-display-xl);
}

.display-l {
  font-size: var(--mx-font-size-display-l);
  line-height: var(--mx-line-height-display-l);
  letter-spacing: var(--mx-tracking-display-l);
}

.display-m {
  font-size: var(--mx-font-size-display-m);
  line-height: var(--mx-line-height-display-m);
  letter-spacing: var(--mx-tracking-display-m);
}

h1,
.h1,
h2,
.h2,
h3,
.h3,
h4,
.h4,
h5,
.h5,
h6,
.h6 {
  font-family: var(--mx-font-heading);
  font-weight: var(--mx-weight-heading);
  color: var(--bs-heading-color);
}

h1,
.h1 {
  font-size: var(--mx-font-size-heading-xl);
  line-height: var(--mx-line-height-heading-xl);
  letter-spacing: var(--mx-tracking-heading-xl);
}

h2,
.h2 {
  font-size: var(--mx-font-size-heading-l);
  line-height: var(--mx-line-height-heading-l);
  letter-spacing: var(--mx-tracking-heading-l);
}

h3,
.h3 {
  font-size: var(--mx-font-size-heading-m);
  line-height: var(--mx-line-height-heading-m);
  letter-spacing: var(--mx-tracking-heading-m);
}

/* h4-h6 are not in the design. [INFERRED] — they step down from Heading M so
   documents using them do not fall back to Bootstrap's unthemed sizes. */
h4,
.h4 {
  font-size: var(--mx-font-size-body-l);
  line-height: var(--mx-line-height-body-l);
}

h5,
.h5 {
  font-size: var(--mx-font-size-body-m);
  line-height: var(--mx-line-height-body-m);
}

h6,
.h6 {
  font-size: var(--mx-font-size-body-s);
  line-height: var(--mx-line-height-body-s);
  letter-spacing: var(--mx-tracking-label);
}

p.lead,
.lead {
  font-size: var(--mx-font-size-body-l);
  line-height: var(--mx-line-height-body-l);
  letter-spacing: var(--mx-tracking-body-l);
  font-weight: var(--mx-weight-body);
  color: var(--mx-text-secondary);
}

p {
  font-size: var(--mx-font-size-body-m);
  line-height: var(--mx-line-height-body-m);
  letter-spacing: var(--mx-tracking-body-m);
}

small,
.small {
  font-size: var(--mx-font-size-body-s);
  line-height: var(--mx-line-height-body-s);
  letter-spacing: var(--mx-tracking-body-s);
  color: var(--mx-text-secondary);
}

/* Form labels and metadata. Body S metrics with primary emphasis and slight
   tracking, so it holds its own next to an input. */
.text-label {
  font-size: var(--mx-font-size-label);
  line-height: var(--mx-line-height-label);
  letter-spacing: var(--mx-tracking-label);
  font-weight: var(--mx-weight-body);
  color: var(--mx-text-primary);
}

/* Section eyebrows — the accent "CATEGORY · OVERLINE" style. */
.text-overline {
  font-size: var(--mx-font-size-overline);
  line-height: var(--mx-line-height-overline);
  letter-spacing: var(--mx-tracking-overline);
  font-weight: var(--mx-weight-body);
  text-transform: uppercase;
  color: var(--mx-accent);
}

/* ===========================================================================
 * 5. BOOTSTRAP COMPONENT BRIDGE
 * ---------------------------------------------------------------------------
 * Each block sets component variables only — no property declarations, no
 * !important. Specificity matches Bootstrap's own selectors and wins on
 * document order, so a tenant overriding a layer-2 token flows all the way
 * through without touching any of this.
 * ======================================================================== */

/* ---- Buttons ---------------------------------------------------------- */
/* Split in two on purpose. Everything here is size-INDEPENDENT and must apply
   to every button, .btn-sm and .btn-lg included. */
.btn {
  --bs-btn-font-family: var(--mx-font-sans);
  --bs-btn-font-weight: var(--mx-weight-body);
  --bs-btn-line-height: 1.5;
  /* [DOC] The design specifies a flat 40% opacity for disabled rather than a
     separate palette, so every variant disables identically. Bootstrap's
     default is .65. */
  --bs-btn-disabled-opacity: 0.4;
  --bs-btn-focus-shadow-rgb: var(--mx-accent-rgb);
  /* Bootstrap bakes an inset black shadow into every variant's
     --bs-btn-active-shadow (and a box-shadow on .btn-link). Neither is emitted
     while Sass $enable-shadows is off in this build — but setting them here
     costs one line and stops them appearing if that ever flips. Declared on
     .btn rather than per variant: same specificity, later in the file than
     Bootstrap's variant blocks, so it wins for all of them at once. */
  --bs-btn-active-shadow: none;
  --bs-btn-box-shadow: none;
}

/* Size-DEPENDENT properties, excluded from .btn-sm / .btn-lg.
 *
 * These are the exact four variables Bootstrap's .btn-sm and .btn-lg exist to
 * override. All three selectors are a single class, so they tie on specificity
 * and the later one wins — and this file loads after Bootstrap. Declared on a
 * bare `.btn` they silently killed every .btn-sm in the app (23 usages), which
 * still carried the class and looked full-size.
 *
 * Same failure mode as .form-control-sm / -lg further down. Whenever the theme
 * sets a variable on a base component, check whether Bootstrap ships a size
 * modifier that sets the same one.
 *
 * :where() keeps the exclusions at ZERO specificity, so this stays a plain
 * (0,1,0) `.btn` for cascade purposes. Without it each :not() counts as a
 * class and the selector out-ranks a tenant's own `.btn` rule even though the
 * tenant sheet loads later — breaking the override contract in the header. */
.btn:where(:not(.btn-sm):not(.btn-lg)) {
  --bs-btn-font-size: var(--mx-font-size-body-m);
  --bs-btn-border-radius: var(--mx-radius);
  /* Padding in baseline units keeps control height on the same 4px grid as
     the type: 12 + 24 + 12 = 48px, matching the design's 48px buttons. */
  --bs-btn-padding-y: calc(var(--mx-baseline-unit) * 3);
  --bs-btn-padding-x: calc(var(--mx-baseline-unit) * 6);
}

/* Primary — solid accent, dark label. [DOC] */
.btn-primary {
  --bs-btn-bg: var(--mx-accent);
  --bs-btn-border-color: var(--mx-accent);
  --bs-btn-color: var(--mx-text-inverse);
  --bs-btn-hover-bg: var(--mx-accent-hover);
  --bs-btn-hover-border-color: var(--mx-accent-hover);
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-bg: var(--mx-accent-strong);
  --bs-btn-active-border-color: var(--mx-accent-strong);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-disabled-bg: var(--mx-accent);
  --bs-btn-disabled-border-color: var(--mx-accent);
  --bs-btn-disabled-color: var(--mx-text-inverse);
}

/* Secondary — solid pink. Not in the mockup, but --bs-secondary maps to the
   pink brand colour so .btn-secondary must be coherent with it. [DERIVED] */
.btn-secondary {
  --bs-btn-bg: var(--mx-secondary);
  --bs-btn-border-color: var(--mx-secondary);
  --bs-btn-color: var(--mx-text-inverse);
  --bs-btn-hover-bg: var(--mx-secondary-hover);
  --bs-btn-hover-border-color: var(--mx-secondary-hover);
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-bg: var(--mx-secondary-hover);
  --bs-btn-active-border-color: var(--mx-secondary-hover);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-disabled-bg: var(--mx-secondary);
  --bs-btn-disabled-border-color: var(--mx-secondary);
  --bs-btn-disabled-color: var(--mx-text-inverse);
}

/*
 * NAMING COLLISION — read before using.
 *
 * The design doc labels the neutral outline button (the white-bordered
 * "Create Account") `.btn-outline-secondary`. But in Bootstrap semantics
 * `secondary` is a theme colour, and this theme maps it to the Streetix pink.
 * So the doc's class name says "pink outline" to Bootstrap and "white outline"
 * to the designer.
 *
 * Resolved in favour of the design, because markup written against the doc
 * will use this class name. `.btn-outline-brand` below is the pink outline for
 * anyone who wants Bootstrap-coherent naming. Worth renaming in Figma —
 * `.btn-outline-neutral` would end the ambiguity.
 */
.btn-outline-secondary {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--mx-border-strong);
  --bs-btn-color: var(--mx-text-primary);
  --bs-btn-hover-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-btn-hover-border-color: var(--mx-text-primary);
  --bs-btn-hover-color: var(--mx-text-primary);
  --bs-btn-active-bg: var(--mx-surface-elevated);
  --bs-btn-active-border-color: var(--mx-text-primary);
  --bs-btn-active-color: var(--mx-text-primary);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--mx-border-default);
  --bs-btn-disabled-color: var(--mx-text-disabled);
  --bs-btn-focus-shadow-rgb: var(--mx-text-primary-rgb);
}

.btn-outline-primary {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--mx-accent);
  --bs-btn-color: var(--mx-accent);
  --bs-btn-hover-bg: var(--mx-accent);
  --bs-btn-hover-border-color: var(--mx-accent);
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-bg: var(--mx-accent-strong);
  --bs-btn-active-border-color: var(--mx-accent-strong);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--mx-accent);
  --bs-btn-disabled-color: var(--mx-accent);
}

/* Pink outline — the Bootstrap-coherent counterpart to .btn-outline-secondary. */
.btn-outline-brand {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--mx-secondary);
  --bs-btn-color: var(--mx-secondary);
  --bs-btn-hover-bg: var(--mx-secondary);
  --bs-btn-hover-border-color: var(--mx-secondary);
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-bg: var(--mx-secondary-hover);
  --bs-btn-active-border-color: var(--mx-secondary-hover);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-focus-shadow-rgb: var(--mx-secondary-rgb);
}

/* Ghost accent — muted accent fill, accent label; the "Forgot Password" style.
   Not a Bootstrap variant, so this is a new class rather than an override. [DOC] */
.btn-ghost-accent {
  --bs-btn-bg: var(--mx-accent-muted);
  --bs-btn-border-color: transparent;
  --bs-btn-color: var(--mx-accent-hover);
  --bs-btn-hover-bg: var(--mx-accent-muted);
  --bs-btn-hover-border-color: var(--mx-accent);
  --bs-btn-hover-color: var(--mx-accent);
  --bs-btn-active-bg: var(--mx-accent-muted);
  --bs-btn-active-border-color: var(--mx-accent);
  --bs-btn-active-color: var(--mx-accent);
  --bs-btn-disabled-bg: var(--mx-accent-muted);
  --bs-btn-disabled-border-color: transparent;
  --bs-btn-disabled-color: var(--mx-accent-hover);
}

.btn-link {
  --bs-btn-color: var(--mx-link);
  --bs-btn-hover-color: var(--mx-link-hover);
  --bs-btn-active-color: var(--mx-accent-strong);
  --bs-btn-disabled-color: var(--mx-text-disabled);
}

.btn-success,
.btn-danger,
.btn-warning,
.btn-info {
  --bs-btn-color: var(--mx-text-inverse);
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-disabled-color: var(--mx-text-inverse);
}

.btn-success {
  --bs-btn-bg: var(--mx-success);
  --bs-btn-border-color: var(--mx-success);
  --bs-btn-hover-bg: var(--mx-success);
  --bs-btn-hover-bg: color-mix(in srgb, var(--mx-success) 85%, var(--mx-text-primary));
  --bs-btn-hover-border-color: var(--bs-btn-hover-bg);
  --bs-btn-active-bg: var(--bs-btn-hover-bg);
  --bs-btn-active-border-color: var(--bs-btn-hover-bg);
  --bs-btn-disabled-bg: var(--mx-success);
  --bs-btn-disabled-border-color: var(--mx-success);
  --bs-btn-focus-shadow-rgb: var(--mx-success-rgb);
}

.btn-danger {
  --bs-btn-bg: var(--mx-error);
  --bs-btn-border-color: var(--mx-error);
  --bs-btn-hover-bg: var(--mx-error);
  --bs-btn-hover-bg: color-mix(in srgb, var(--mx-error) 85%, var(--mx-text-primary));
  --bs-btn-hover-border-color: var(--bs-btn-hover-bg);
  --bs-btn-active-bg: var(--bs-btn-hover-bg);
  --bs-btn-active-border-color: var(--bs-btn-hover-bg);
  --bs-btn-disabled-bg: var(--mx-error);
  --bs-btn-disabled-border-color: var(--mx-error);
  --bs-btn-focus-shadow-rgb: var(--mx-error-rgb);
}

.btn-warning {
  --bs-btn-bg: var(--mx-warning);
  --bs-btn-border-color: var(--mx-warning);
  --bs-btn-hover-bg: var(--mx-warning);
  --bs-btn-hover-bg: color-mix(in srgb, var(--mx-warning) 85%, var(--mx-text-primary));
  --bs-btn-hover-border-color: var(--bs-btn-hover-bg);
  --bs-btn-active-bg: var(--bs-btn-hover-bg);
  --bs-btn-active-border-color: var(--bs-btn-hover-bg);
  --bs-btn-disabled-bg: var(--mx-warning);
  --bs-btn-disabled-border-color: var(--mx-warning);
  --bs-btn-focus-shadow-rgb: var(--mx-warning-rgb);
}

.btn-info {
  --bs-btn-bg: var(--mx-info);
  --bs-btn-border-color: var(--mx-info);
  --bs-btn-hover-bg: var(--mx-info);
  --bs-btn-hover-bg: color-mix(in srgb, var(--mx-info) 85%, var(--mx-text-primary));
  --bs-btn-hover-border-color: var(--bs-btn-hover-bg);
  --bs-btn-active-bg: var(--bs-btn-hover-bg);
  --bs-btn-active-border-color: var(--bs-btn-hover-bg);
  --bs-btn-disabled-bg: var(--mx-info);
  --bs-btn-disabled-border-color: var(--mx-info);
  --bs-btn-focus-shadow-rgb: var(--mx-info-rgb);
}

/* Outline status variants — transparent until hovered, then they fill. */
.btn-outline-success,
.btn-outline-danger,
.btn-outline-warning,
.btn-outline-info {
  --bs-btn-bg: transparent;
  --bs-btn-hover-color: var(--mx-text-inverse);
  --bs-btn-active-color: var(--mx-text-inverse);
  --bs-btn-disabled-bg: transparent;
}

.btn-outline-success {
  --bs-btn-color: var(--mx-success);
  --bs-btn-border-color: var(--mx-success);
  --bs-btn-hover-bg: var(--mx-success);
  --bs-btn-hover-border-color: var(--mx-success);
  --bs-btn-active-bg: var(--mx-success);
  --bs-btn-active-border-color: var(--mx-success);
  --bs-btn-disabled-color: var(--mx-success);
  --bs-btn-disabled-border-color: var(--mx-success);
  --bs-btn-focus-shadow-rgb: var(--mx-success-rgb);
}

.btn-outline-danger {
  --bs-btn-color: var(--mx-error);
  --bs-btn-border-color: var(--mx-error);
  --bs-btn-hover-bg: var(--mx-error);
  --bs-btn-hover-border-color: var(--mx-error);
  --bs-btn-active-bg: var(--mx-error);
  --bs-btn-active-border-color: var(--mx-error);
  --bs-btn-disabled-color: var(--mx-error);
  --bs-btn-disabled-border-color: var(--mx-error);
  --bs-btn-focus-shadow-rgb: var(--mx-error-rgb);
}

.btn-outline-warning {
  --bs-btn-color: var(--mx-warning);
  --bs-btn-border-color: var(--mx-warning);
  --bs-btn-hover-bg: var(--mx-warning);
  --bs-btn-hover-border-color: var(--mx-warning);
  --bs-btn-active-bg: var(--mx-warning);
  --bs-btn-active-border-color: var(--mx-warning);
  --bs-btn-disabled-color: var(--mx-warning);
  --bs-btn-disabled-border-color: var(--mx-warning);
  --bs-btn-focus-shadow-rgb: var(--mx-warning-rgb);
}

.btn-outline-info {
  --bs-btn-color: var(--mx-info);
  --bs-btn-border-color: var(--mx-info);
  --bs-btn-hover-bg: var(--mx-info);
  --bs-btn-hover-border-color: var(--mx-info);
  --bs-btn-active-bg: var(--mx-info);
  --bs-btn-active-border-color: var(--mx-info);
  --bs-btn-disabled-color: var(--mx-info);
  --bs-btn-disabled-border-color: var(--mx-info);
  --bs-btn-focus-shadow-rgb: var(--mx-info-rgb);
}

/* ---- Neutral variants: light / dark ------------------------------------
 * These were the real hole. Bootstrap bakes .btn-light at #f8f9fa — a glaring
 * near-white slab on a dark page — and it is this app's Cancel button in 13
 * places. Nothing in the theme touched it, so it kept Bootstrap's palette in
 * every state.
 *
 * .btn-light is deliberately mapped to the NEUTRAL SECONDARY role rather than
 * literally "light". That is how the app uses it (Cancel next to a primary
 * Save), and a literal near-white button would out-shout the accent it sits
 * beside. Same reasoning as .btn-outline-secondary being neutral.
 *
 * .btn-dark stays literally dark in both modes, because a caller writing
 * "dark" means it. It carries a border so it stays visible against a dark
 * page — without one it disappears entirely in this theme. */
.btn-light {
  --bs-btn-color: var(--mx-text-primary);
  --bs-btn-bg: var(--mx-surface-elevated);
  --bs-btn-border-color: var(--mx-border-default);
  --bs-btn-hover-color: var(--mx-text-primary);
  --bs-btn-hover-bg: var(--mx-surface-overlay);
  --bs-btn-hover-bg: color-mix(in srgb, var(--mx-surface-elevated) 92%, var(--mx-text-primary));
  --bs-btn-hover-border-color: var(--mx-border-strong);
  --bs-btn-active-color: var(--mx-text-primary);
  --bs-btn-active-bg: var(--mx-surface-overlay);
  --bs-btn-active-bg: color-mix(in srgb, var(--mx-surface-elevated) 86%, var(--mx-text-primary));
  --bs-btn-active-border-color: var(--mx-border-strong);
  --bs-btn-disabled-color: var(--mx-text-disabled);
  --bs-btn-disabled-bg: var(--mx-surface-elevated);
  --bs-btn-disabled-border-color: var(--mx-border-default);
  --bs-btn-focus-shadow-rgb: var(--mx-text-primary-rgb);
}

.btn-outline-light {
  --bs-btn-color: var(--mx-text-primary);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--mx-border-strong);
  --bs-btn-hover-color: var(--mx-text-primary);
  --bs-btn-hover-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-btn-hover-border-color: var(--mx-text-primary);
  --bs-btn-active-color: var(--mx-text-primary);
  --bs-btn-active-bg: var(--mx-surface-overlay);
  --bs-btn-active-border-color: var(--mx-text-primary);
  --bs-btn-disabled-color: var(--mx-text-disabled);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--mx-border-default);
  --bs-btn-focus-shadow-rgb: var(--mx-text-primary-rgb);
}

.btn-dark {
  --bs-btn-color: var(--mx-neutral-0);
  --bs-btn-bg: var(--mx-neutral-950);
  --bs-btn-border-color: var(--mx-border-strong);
  --bs-btn-hover-color: var(--mx-neutral-0);
  --bs-btn-hover-bg: var(--mx-neutral-800);
  --bs-btn-hover-border-color: var(--mx-border-strong);
  --bs-btn-active-color: var(--mx-neutral-0);
  --bs-btn-active-bg: var(--mx-neutral-700);
  --bs-btn-active-border-color: var(--mx-border-strong);
  --bs-btn-disabled-color: var(--mx-neutral-0);
  --bs-btn-disabled-bg: var(--mx-neutral-950);
  --bs-btn-disabled-border-color: var(--mx-border-strong);
  --bs-btn-focus-shadow-rgb: var(--mx-neutral-500-rgb);
}

.btn-outline-dark {
  --bs-btn-color: var(--mx-text-primary);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--mx-border-strong);
  --bs-btn-hover-color: var(--mx-neutral-0);
  --bs-btn-hover-bg: var(--mx-neutral-950);
  --bs-btn-hover-border-color: var(--mx-neutral-950);
  --bs-btn-active-color: var(--mx-neutral-0);
  --bs-btn-active-bg: var(--mx-neutral-950);
  --bs-btn-active-border-color: var(--mx-neutral-950);
  --bs-btn-disabled-color: var(--mx-text-disabled);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--mx-border-default);
  --bs-btn-focus-shadow-rgb: var(--mx-neutral-500-rgb);
}

/* ---- Cards ------------------------------------------------------------
 * These parameters are tuned so a bare `.card` / `.card-header` / `.card-body`
 * reproduces the geometry of the legacy Inspinia `.ibox` it replaces, letting
 * that markup migrate to stock Bootstrap classes with no bespoke CSS.
 * Padding is in baseline units, so cards sit on the same 4px grid as the type.
 *
 * NOTE: --bs-card-box-shadow is deliberately absent. Bootstrap declares it but
 * never reads it (Sass $enable-shadows is off in this build), so setting it
 * would be a silent no-op. Use the .shadow-sm utility in markup instead. */
.card {
  --bs-card-bg: var(--mx-surface-default);
  --bs-card-color: var(--mx-text-primary);
  --bs-card-border-color: var(--mx-border-subtle);
  --bs-card-border-radius: var(--mx-radius-lg);
  --bs-card-inner-border-radius: calc(var(--mx-radius-lg) - 1px);
  --bs-card-cap-bg: var(--mx-surface-elevated);
  --bs-card-cap-color: var(--mx-text-primary);
  --bs-card-title-color: var(--mx-text-heading);
  --bs-card-subtitle-color: var(--mx-text-secondary);
  /* .ibox-content was 15px 20px 20px 20px */
  --bs-card-spacer-y: calc(var(--mx-baseline-unit) * 4);
  --bs-card-spacer-x: calc(var(--mx-baseline-unit) * 5);
  /* .ibox-title was 14px 15px 7px with a hard height: 48px that clipped long
     titles. Same visual weight, but the header now auto-heights. */
  --bs-card-cap-padding-y: calc(var(--mx-baseline-unit) * 3);
  --bs-card-cap-padding-x: calc(var(--mx-baseline-unit) * 5);
}

/* .ibox-title held an <h5> sized 14px. Bootstrap leaves heading sizing to the
   type scale, which would render that h5 at 16px — close enough to keep, but
   the margin reset is needed or the heading pushes the header out of shape. */
.card-header > h1,
.card-header > h2,
.card-header > h3,
.card-header > h4,
.card-header > h5,
.card-header > h6 {
  margin-bottom: 0;
}

/* ---- Dropdowns -------------------------------------------------------- */
/* Hover/active states are an alpha tint of the foreground, not the next surface
   token. The light surface ladder is only ~3% apart end to end, so a surface
   step computes to the same colour there while reading fine in dark. */
.dropdown-menu {
  --bs-dropdown-bg: var(--mx-surface-overlay);
  --bs-dropdown-color: var(--mx-text-primary);
  --bs-dropdown-border-color: var(--mx-border-default);
  --bs-dropdown-border-radius: var(--mx-radius);
  --bs-dropdown-divider-bg: var(--mx-border-subtle);
  --bs-dropdown-header-color: var(--mx-text-tertiary);
  --bs-dropdown-link-color: var(--mx-text-primary);
  --bs-dropdown-link-hover-color: var(--mx-text-primary);
  --bs-dropdown-link-hover-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-dropdown-link-active-color: var(--mx-text-inverse);
  --bs-dropdown-link-active-bg: var(--mx-accent);
  --bs-dropdown-link-disabled-color: var(--mx-text-disabled);
}

/* Bootstrap DECLARES --bs-dropdown-box-shadow but never reads it — the
   property is only emitted when Sass $enable-shadows was true at compile
   time, and this build has it off. Verified against bootstrap-5.3.8. Same
   applies to modal / popover / offcanvas below, so those four take a real
   declaration. Depth matters more in dark mode than light: without a shadow
   an overlay and the page behind it read as one flat plane. */
.dropdown-menu {
  box-shadow: var(--mx-shadow-overlay);
}

/* ---- Modals ----------------------------------------------------------- */
.modal {
  --bs-modal-bg: var(--mx-surface-overlay);
  --bs-modal-color: var(--mx-text-primary);
  --bs-modal-border-color: var(--mx-border-default);
  --bs-modal-border-radius: var(--mx-radius-lg);
  --bs-modal-header-border-color: var(--mx-border-subtle);
  --bs-modal-footer-border-color: var(--mx-border-subtle);
}

/* See the dropdown note — --bs-modal-box-shadow is inert in this build. */
.modal-content {
  box-shadow: var(--mx-shadow-overlay);
}

/* ---- Offcanvas -------------------------------------------------------- */
.offcanvas,
.offcanvas-lg,
.offcanvas-md,
.offcanvas-sm,
.offcanvas-xl,
.offcanvas-xxl {
  --bs-offcanvas-bg: var(--mx-surface-overlay);
  --bs-offcanvas-color: var(--mx-text-primary);
  --bs-offcanvas-border-color: var(--mx-border-default);
}

/* See the dropdown note — --bs-offcanvas-box-shadow is inert in this build. */
.offcanvas.show,
.offcanvas-lg.show,
.offcanvas-md.show,
.offcanvas-sm.show,
.offcanvas-xl.show,
.offcanvas-xxl.show {
  box-shadow: var(--mx-shadow-overlay);
}

/* ---- Nav / tabs / pills ----------------------------------------------- */
.nav {
  --bs-nav-link-color: var(--mx-text-secondary);
  --bs-nav-link-hover-color: var(--mx-text-primary);
  --bs-nav-link-disabled-color: var(--mx-text-disabled);
  --bs-nav-link-font-weight: var(--mx-weight-body);
}

.nav-tabs {
  --bs-nav-tabs-border-color: var(--mx-border-subtle);
  --bs-nav-tabs-link-hover-border-color: var(--mx-border-default);
  --bs-nav-tabs-link-active-color: var(--mx-text-primary);
  --bs-nav-tabs-link-active-bg: var(--mx-surface-default);
  --bs-nav-tabs-link-active-border-color: var(--mx-border-default);
  --bs-nav-tabs-border-radius: var(--mx-radius);
}

.nav-pills {
  --bs-nav-pills-link-active-color: var(--mx-text-inverse);
  --bs-nav-pills-link-active-bg: var(--mx-accent);
  --bs-nav-pills-border-radius: var(--mx-radius);
}

.nav-underline {
  --bs-nav-underline-link-active-color: var(--mx-accent);
}

.navbar {
  --bs-navbar-color: var(--mx-text-secondary);
  --bs-navbar-hover-color: var(--mx-text-primary);
  --bs-navbar-active-color: var(--mx-accent);
  --bs-navbar-disabled-color: var(--mx-text-disabled);
  --bs-navbar-brand-color: var(--mx-text-primary);
  --bs-navbar-brand-hover-color: var(--mx-text-primary);
}

/* ---- Tables ----------------------------------------------------------- */
.table {
  --bs-table-color: var(--mx-text-primary);
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--mx-border-subtle);
  --bs-table-striped-color: var(--mx-text-primary);
  --bs-table-striped-bg: rgba(var(--mx-text-primary-rgb), 0.04);
  --bs-table-hover-color: var(--mx-text-primary);
  --bs-table-hover-bg: rgba(var(--mx-text-primary-rgb), 0.07);
  --bs-table-active-color: var(--mx-text-primary);
  --bs-table-active-bg: rgba(var(--mx-accent-rgb), 0.12);
}

/* ---- Alerts ----------------------------------------------------------- */
.alert {
  --bs-alert-border-radius: var(--mx-radius);
}

/* ---- List groups ------------------------------------------------------ */
.list-group {
  --bs-list-group-color: var(--mx-text-primary);
  --bs-list-group-bg: var(--mx-surface-default);
  --bs-list-group-border-color: var(--mx-border-subtle);
  --bs-list-group-border-radius: var(--mx-radius);
  --bs-list-group-action-color: var(--mx-text-secondary);
  --bs-list-group-action-hover-color: var(--mx-text-primary);
  --bs-list-group-action-hover-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-list-group-action-active-color: var(--mx-text-primary);
  --bs-list-group-action-active-bg: rgba(var(--mx-text-primary-rgb), 0.13);
  --bs-list-group-active-color: var(--mx-text-inverse);
  --bs-list-group-active-bg: var(--mx-accent);
  --bs-list-group-active-border-color: var(--mx-accent);
  --bs-list-group-disabled-color: var(--mx-text-disabled);
  --bs-list-group-disabled-bg: var(--mx-surface-default);
}

/* ---- Pagination ------------------------------------------------------- */
.pagination {
  --bs-pagination-color: var(--mx-text-secondary);
  --bs-pagination-bg: var(--mx-surface-default);
  --bs-pagination-border-color: var(--mx-border-subtle);
  --bs-pagination-hover-color: var(--mx-text-primary);
  --bs-pagination-hover-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-pagination-hover-border-color: var(--mx-border-default);
  --bs-pagination-focus-color: var(--mx-text-primary);
  --bs-pagination-focus-bg: rgba(var(--mx-text-primary-rgb), 0.08);
  --bs-pagination-focus-box-shadow: 0 0 0 var(--mx-focus-ring-width)
    rgba(var(--mx-accent-rgb), var(--mx-focus-ring-opacity));
  --bs-pagination-active-color: var(--mx-text-inverse);
  --bs-pagination-active-bg: var(--mx-accent);
  --bs-pagination-active-border-color: var(--mx-accent);
  --bs-pagination-disabled-color: var(--mx-text-disabled);
  --bs-pagination-disabled-bg: var(--mx-surface-default);
  --bs-pagination-disabled-border-color: var(--mx-border-subtle);
}

/* Radius is the one pagination variable .pagination-sm / -lg also set, so it
   needs the same guard as .btn — the DataTable uses .pagination-sm and was
   getting the full-size radius. */
.pagination:not(.pagination-sm):not(.pagination-lg) {
  --bs-pagination-border-radius: var(--mx-radius);
}

/* ---- Accordion -------------------------------------------------------- */
.accordion {
  --bs-accordion-color: var(--mx-text-primary);
  --bs-accordion-bg: var(--mx-surface-default);
  --bs-accordion-border-color: var(--mx-border-subtle);
  --bs-accordion-border-radius: var(--mx-radius);
  --bs-accordion-btn-color: var(--mx-text-primary);
  --bs-accordion-btn-bg: var(--mx-surface-default);
  --bs-accordion-active-color: var(--mx-accent);
  --bs-accordion-active-bg: var(--mx-accent-muted);
  --bs-accordion-btn-focus-box-shadow: 0 0 0 var(--mx-focus-ring-width)
    rgba(var(--mx-accent-rgb), var(--mx-focus-ring-opacity));
}

/* ---- Toasts, tooltips, popovers, progress, breadcrumb, badge ----------- */
.toast {
  --bs-toast-bg: var(--mx-surface-overlay);
  --bs-toast-color: var(--mx-text-primary);
  --bs-toast-border-color: var(--mx-border-default);
  --bs-toast-border-radius: var(--mx-radius);
  --bs-toast-header-bg: var(--mx-surface-elevated);
  --bs-toast-header-color: var(--mx-text-secondary);
  --bs-toast-header-border-color: var(--mx-border-subtle);
  --bs-toast-box-shadow: var(--mx-shadow-overlay);
}

.tooltip {
  --bs-tooltip-bg: var(--mx-surface-overlay);
  --bs-tooltip-color: var(--mx-text-primary);
  --bs-tooltip-border-radius: var(--mx-radius-sm);
  --bs-tooltip-opacity: 1;
}

.popover {
  --bs-popover-bg: var(--mx-surface-overlay);
  --bs-popover-body-color: var(--mx-text-primary);
  --bs-popover-border-color: var(--mx-border-default);
  --bs-popover-border-radius: var(--mx-radius);
  --bs-popover-header-bg: var(--mx-surface-elevated);
  --bs-popover-header-color: var(--mx-text-primary);
}

/* See the dropdown note — --bs-popover-box-shadow is inert in this build. */
.popover {
  box-shadow: var(--mx-shadow-overlay);
}

.progress,
.progress-stacked {
  --bs-progress-bg: var(--mx-surface-elevated);
  --bs-progress-bar-bg: var(--mx-accent);
  --bs-progress-bar-color: var(--mx-text-inverse);
  --bs-progress-border-radius: var(--mx-radius-pill);
}

.breadcrumb {
  --bs-breadcrumb-divider-color: var(--mx-text-tertiary);
  --bs-breadcrumb-item-active-color: var(--mx-text-primary);
}

.badge {
  --bs-badge-border-radius: var(--mx-radius-sm);
  --bs-badge-font-weight: var(--mx-weight-body);
  --bs-badge-font-size: var(--mx-font-size-overline);
}

/* ===========================================================================
 * 6. GAPS — where Bootstrap 5.3 has no variable
 * ---------------------------------------------------------------------------
 * Forms are the main one: .form-control is still Sass-compiled, so only
 * validation colours are variables. The base element already reads
 * --bs-body-bg / --bs-body-color / --bs-border-color / --bs-border-radius,
 * so it themes itself from section 3. What it does NOT read is :focus, which
 * hardcodes #86b7fe and rgba(13,110,253,.25) — Bootstrap blue. Those are the
 * declarations below.
 * ======================================================================== */

/* :where() for the same reason as .btn above: the size exclusions must not
   add specificity, or tenant overrides on a plain .form-control lose. */
/* All sizes: detach the fill from --bs-body-bg (Bootstrap's hardcoded choice)
   so tenants can retint fields independently of the page. Defaults identical —
   --mx-field-bg resolves to bg-base until someone overrides it. */
.form-control,
.form-select {
  background-color: var(--mx-field-bg);
}

.form-control:where(:not(.form-control-sm):not(.form-control-lg)),
.form-select:where(:not(.form-select-sm):not(.form-select-lg)) {
  /* Same 48px control height as .btn — see the padding note there. */
  padding: calc(var(--mx-baseline-unit) * 3) calc(var(--mx-baseline-unit) * 4);
  font-size: var(--mx-font-size-body-m);
  line-height: 1.5;
}

.form-control::placeholder {
  color: var(--mx-text-tertiary);
  opacity: 1; /* Firefox dims placeholders by default; the token already is dim. */
}

.form-control:-webkit-autofill,
.form-control:-webkit-autofill:hover,
.form-control:-webkit-autofill:focus,
.form-select:-webkit-autofill {
  -webkit-text-fill-color: var(--mx-text-primary);
  -webkit-box-shadow: 0 0 0 1000px var(--mx-bg-base) inset;
  box-shadow: 0 0 0 1000px var(--mx-bg-base) inset;
  caret-color: var(--mx-text-primary);
  transition: background-color 600000s 0s, color 600000s 0s;
}

.form-control:autofill,
.form-control:autofill:hover,
.form-control:autofill:focus,
.form-select:autofill {
  -webkit-text-fill-color: var(--mx-text-primary);
  box-shadow: 0 0 0 1000px var(--mx-bg-base) inset;
  caret-color: var(--mx-text-primary);
}

/* Focus — accent border plus the "teal glow" the design calls for. [DOC]
   The rgba line is a literal fallback for engines without color-mix(); the
   second declaration wins wherever it is supported. */
.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  border-color: var(--mx-accent);
  outline: 0;
  box-shadow: 0 0 0 var(--mx-focus-ring-width)
    rgba(var(--mx-accent-rgb), var(--mx-focus-ring-opacity));
}

/* Error — same treatment in the error hue. .is-invalid is Bootstrap's own
   validation hook, so server-rendered forms pick this up for free. */
.form-control.is-invalid:focus,
.form-select.is-invalid:focus,
.was-validated .form-control:invalid:focus {
  border-color: var(--mx-error);
  box-shadow: 0 0 0 var(--mx-focus-ring-width)
    rgba(var(--mx-error-rgb), var(--mx-focus-ring-opacity));
}

.form-check-input:checked {
  background-color: var(--mx-accent);
  border-color: var(--mx-accent);
}

.form-label {
  font-size: var(--mx-font-size-label);
  line-height: var(--mx-line-height-label);
  letter-spacing: var(--mx-tracking-label);
  color: var(--mx-text-primary);
  margin-bottom: calc(var(--mx-baseline-unit) * 2);
  margin-left: var(--mx-baseline-unit);
}

.form-text {
  color: var(--mx-text-tertiary);
  font-size: var(--mx-font-size-body-s);
}

/* ===========================================================================
 * 7. UTILITIES
 * ---------------------------------------------------------------------------
 * Bootstrap's .text-primary / .bg-primary already resolve through the bridge.
 * These cover the semantic slots Bootstrap has no equivalent for.
 * ======================================================================== */
.text-primary-mx {
  color: var(--mx-text-primary) !important;
}
.text-secondary-mx {
  color: var(--mx-text-secondary) !important;
}
.text-tertiary-mx {
  color: var(--mx-text-tertiary) !important;
}
.text-accent-mx {
  color: var(--mx-accent) !important;
}

.bg-base-mx {
  background-color: var(--mx-bg-base) !important;
}
.bg-subtle-mx {
  background-color: var(--mx-bg-subtle) !important;
}
.bg-muted-mx {
  background-color: var(--mx-bg-muted) !important;
}

.surface-default {
  background-color: var(--mx-surface-default);
}
.surface-elevated {
  background-color: var(--mx-surface-elevated);
}
.surface-overlay {
  background-color: var(--mx-surface-overlay);
}

.border-subtle-mx {
  border-color: var(--mx-border-subtle) !important;
}
.border-strong-mx {
  border-color: var(--mx-border-strong) !important;
}