/* =============================================================================
   theme-bridge.css  —  theme-agnostic compatibility layer
   -----------------------------------------------------------------------------
   Purpose: the classic (Bootstrap-based) DevExpress themes ship Bootstrap's
   classes + --bs-* variables; the Fluent themes ship NEITHER (they theme via
   --dxds-* tokens). This file fills the gap WITHOUT forcing any static palette:

     * It NEVER sets --bs-* or a body/page background (that froze the theme).
     * Every color resolves through a fallback chain:
         --bs-* (classic themes)  ->  --dxds-* (Fluent)  ->  last-resort literal.
       So under classic themes the values equal Bootstrap's own (no visual change),
       under Fluent they pick up the Fluent tokens, and the literal is only ever a
       safety net that an active theme never reaches.
     * Loaded BEFORE the theme <link>, so the active theme still overrides anything
       here on the classic themes; under Fluent (which defines none of these) the
       rules below apply.

   Bootstrap GRID + flex/align/order/spacing come from bootstrap-grid.min.css.
   This file adds the remaining utilities (gutters, gap, text, position, sizing,
   borders, color utilities) and minimal themed components (card/badge/btn/alert/
   spinner) that Fluent does not provide.
   ============================================================================= */

:root {
  --app-surface: var(--bs-body-bg, var(--dxds-color-surface-neutral-default-rest, #ffffff));
  --app-fg: var(--bs-body-color, var(--dxds-color-content-neutral-default-rest, #1f2933));
  --app-muted: var(--bs-secondary-color, var(--dxds-color-content-neutral-subdued-rest, #6b7280));
  --app-border: var(--bs-border-color, var(--dxds-color-border-neutral-default-rest, #e5e7eb));
  --app-primary: var(--bs-primary, var(--dxds-color-content-primary-default-rest, #2563eb));
  --app-success: var(--bs-success, var(--dxds-color-content-success-default-rest, #16a34a));
  --app-danger: var(--bs-danger, var(--dxds-color-content-danger-default-rest, #dc2626));
  --app-warning: var(--bs-warning, var(--dxds-color-content-warning-default-rest, #d97706));
  --app-info: var(--bs-info, var(--dxds-color-content-info-default-rest, #0dcaf0));
  /* soft elevated surface derived from the resolved surface/fg (works light + dark) */
  --app-surface-soft: color-mix(in srgb, var(--app-fg) 4%, var(--app-surface));
  /* neutral hover/active fill — a touch stronger than surface-soft (works light + dark) */
  --app-surface-hover: color-mix(in srgb, var(--app-fg) 8%, var(--app-surface));
  /* tinted "soft" fills for hover/selected/badge states — accent mixed into the surface,
     so they go light in light themes and dark in dark themes instead of staying a fixed
     pale literal. Use these anywhere a #eff6ff / #dbeafe / #fef2f2-style tint was hardcoded. */
  --app-primary-soft:  color-mix(in srgb, var(--app-primary) 12%, var(--app-surface));
  --app-primary-soft-strong: color-mix(in srgb, var(--app-primary) 22%, var(--app-surface));
  --app-success-soft:  color-mix(in srgb, var(--app-success) 12%, var(--app-surface));
  --app-danger-soft:   color-mix(in srgb, var(--app-danger) 12%, var(--app-surface));
  --app-warning-soft:  color-mix(in srgb, var(--app-warning) 15%, var(--app-surface));
  /* soft tinted borders (for the light-blue/red outlines that paired with the tints above) */
  --app-primary-border: color-mix(in srgb, var(--app-primary) 35%, var(--app-surface));
  --app-danger-border:  color-mix(in srgb, var(--app-danger) 35%, var(--app-surface));
  --app-success-border: color-mix(in srgb, var(--app-success) 35%, var(--app-surface));
  --app-warning-border: color-mix(in srgb, var(--app-warning) 35%, var(--app-surface));
  /* font tokens — resolves to the active theme's body font variable, then the Fluent token,
     then a safe system-font fallback. Classic DX themes (e.g. Office White) set
     body { font-family } directly without a CSS variable, so component shells should
     OMIT font-family entirely and rely on inheritance from body, which always carries the
     correct theme font. Use --app-font-family only when an explicit declaration is required. */
  --app-font-family: var(--bs-body-font-family, var(--dxds-t-font-family, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif));
  --app-font-size-base: var(--bs-body-font-size, var(--dxds-t-font-size-m, 0.875rem));
}

/* -----------------------------------------------------------------------------
   --bs-* fallback for the Fluent themes — inside a CASCADE LAYER.
   Layered declarations always lose to the theme's UNLAYERED declarations, so:
     * classic (bs5) themes  -> their own --bs-* win; this block is ignored.
     * Fluent themes (define no --bs-*) -> these map --bs-* onto Fluent --dxds-*.
   Effect: any component styled with `var(--bs-*, fallback)` (e.g. the dashboards)
   themes correctly under Fluent WITHOUT editing the component, and never overrides
   the classic themes (order-independent via @layer). No static palette.
   NOTE: this only helps components that read --bs-* vars; components with hardcoded
   literals (e.g. background:#fff) still need their own values pointed at --app-*.
   ----------------------------------------------------------------------------- */
@layer dx-bridge-fallback {
    :root {
        --bs-body-bg: var(--dxds-color-surface-neutral-default-rest);
        --bs-body-color: var(--dxds-color-content-neutral-default-rest);
        --bs-emphasis-color: var(--dxds-color-content-neutral-default-rest);
        --bs-secondary: var(--dxds-color-content-neutral-subdued-rest);
        --bs-secondary-color: var(--dxds-color-content-neutral-subdued-rest);
        --bs-tertiary-color: var(--dxds-color-content-neutral-subdued-rest);
        --bs-border-color: var(--dxds-color-border-neutral-default-rest);
        --bs-primary: var(--dxds-color-content-primary-default-rest);
        --bs-success: var(--dxds-color-content-success-default-rest);
        --bs-danger: var(--dxds-color-content-danger-default-rest);
        --bs-warning: var(--dxds-color-content-warning-default-rest);
        --bs-info: var(--dxds-color-content-info-default-rest);
        /* Subtle elevated surfaces (Bootstrap's --bs-secondary-bg / --bs-tertiary-bg).
       Fluent ships no equivalent token, so derive them from the resolved
       content/surface tokens with color-mix — adapts correctly in light AND dark.
       tertiary = lightest fill (Bootstrap #f8f9fa), secondary = slightly stronger (#e9ecef). */
        --bs-tertiary-bg: color-mix(in srgb, var(--dxds-color-content-neutral-default-rest) 4%, var(--dxds-color-surface-neutral-default-rest));
        --bs-secondary-bg: color-mix(in srgb, var(--dxds-color-content-neutral-default-rest) 7%, var(--dxds-color-surface-neutral-default-rest));
        /* Font: map Bootstrap's body font vars to Fluent's own token so --app-font-family
       and any component that reads --bs-body-font-family both resolve correctly. */
        --bs-body-font-family: var(--dxds-t-font-family, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
        --bs-body-font-size: var(--dxds-t-font-size-m, 0.875rem);
    }
  /* Apply Fluent's font token directly to body so components that simply inherit
     (the preferred pattern) match the active Fluent font without any explicit override.
     Layered rule loses to unlayered — classic themes' direct body rules always win. */
    body {
        font-family: var(--app-font-family);
        font-size: var(--app-font-size-base);
    }
}

/* ---- gutters (.g-*) + gap (not included in bootstrap-grid) ---- */
.g-0 {
  --bs-gutter-x: 0;
  --bs-gutter-y: 0;
}

.g-1 {
  --bs-gutter-x: .25rem;
  --bs-gutter-y: .25rem;
}

.g-2 {
  --bs-gutter-x: .5rem;
  --bs-gutter-y: .5rem;
}

.g-3 {
  --bs-gutter-x: 1rem;
  --bs-gutter-y: 1rem;
}

.g-4 {
  --bs-gutter-x: 1.5rem;
  --bs-gutter-y: 1.5rem;
}

.g-5 {
  --bs-gutter-x: 3rem;
  --bs-gutter-y: 3rem;
}

.gap-0 {
  gap: 0 !important;
}

.gap-1 {
  gap: .25rem !important;
}

.gap-2 {
  gap: .5rem !important;
}

.gap-3 {
  gap: 1rem !important;
}

.gap-4 {
  gap: 1.5rem !important;
}

.gap-5 {
  gap: 3rem !important;
}

/* ---- text utilities ---- */
.text-start {
  text-align: left !important;
}

.text-center {
  text-align: center !important;
}

.text-end {
  text-align: right !important;
}

.text-nowrap {
  white-space: nowrap !important;
}

.text-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.text-uppercase {
  text-transform: uppercase !important;
}

.text-lowercase {
  text-transform: lowercase !important;
}

.text-capitalize {
  text-transform: capitalize !important;
}

.fw-light {
  font-weight: 300 !important;
}

.fw-normal {
  font-weight: 400 !important;
}

.fw-medium {
  font-weight: 500 !important;
}

.fw-semibold {
  font-weight: 600 !important;
}

.fw-bold {
  font-weight: 700 !important;
}

.fw-lighter {
  font-weight: lighter !important;
}

.fw-bolder {
  font-weight: bolder !important;
}

/* font sizes (.fs-1 .. .fs-6) */
.fs-1 { font-size: calc(1.375rem + 1.5vw) !important; }
.fs-2 { font-size: calc(1.325rem + .9vw) !important; }
.fs-3 { font-size: calc(1.3rem + .6vw) !important; }
.fs-4 { font-size: calc(1.275rem + .3vw) !important; }
.fs-5 { font-size: 1.25rem !important; }
.fs-6 { font-size: 1rem !important; }

.fst-italic {
  font-style: italic !important;
}

.fst-normal {
  font-style: normal !important;
}

.text-decoration-none {
  text-decoration: none !important;
}

.text-decoration-underline {
  text-decoration: underline !important;
}

.text-decoration-line-through {
  text-decoration: line-through !important;
}

.small {
  font-size: .875em;
}

.lh-1 {
  line-height: 1 !important;
}

.lh-sm {
  line-height: 1.25 !important;
}

.lh-base {
  line-height: 1.5 !important;
}

.lh-lg {
  line-height: 2 !important;
}

/* ---- text colors (each maps to its own --bs var first, so classic is identical) ---- */
.text-primary {
  color: var(--app-primary) !important;
}

.text-secondary {
  color: var(--app-muted) !important;
}

.text-success {
  color: var(--app-success) !important;
}

.text-danger {
  color: var(--app-danger) !important;
}

.text-warning {
  color: var(--app-warning) !important;
}

.text-info {
  color: var(--app-info) !important;
}

.text-muted {
  color: var(--app-muted) !important;
}

.text-body {
  color: var(--app-fg) !important;
}

.text-dark {
  color: var(--bs-dark, var(--dxds-color-content-neutral-default-rest, #212529)) !important;
}

.text-light {
  color: var(--bs-light, #f8f9fa) !important;
}

.text-white {
  color: #fff !important;
}

.text-black {
  color: #000 !important;
}

/* ---- background colors ---- */
.bg-white {
  background-color: var(--bs-white, var(--dxds-color-surface-neutral-default-rest, #fff)) !important;
}

.bg-body {
  background-color: var(--app-surface) !important;
}

.bg-light {
  background-color: var(--bs-light, var(--app-surface-soft)) !important;
}

.bg-primary {
  background-color: var(--app-primary) !important;
}

.bg-secondary {
  background-color: var(--bs-secondary-bg, var(--app-surface-soft)) !important;
}

.bg-success {
  background-color: var(--app-success) !important;
}

.bg-danger {
  background-color: var(--app-danger) !important;
}

.bg-warning {
  background-color: var(--app-warning) !important;
}

.bg-info {
  background-color: var(--app-info) !important;
}

.bg-dark {
  background-color: var(--bs-dark, #212529) !important;
}

.bg-transparent {
  background-color: transparent !important;
}

/* ---- borders / radius / shadow ---- */
.border {
  border: 1px solid var(--app-border) !important;
}

.border-0 {
  border: 0 !important;
}

.border-top {
  border-top: 1px solid var(--app-border) !important;
}

.border-bottom {
  border-bottom: 1px solid var(--app-border) !important;
}

.border-start {
  border-left: 1px solid var(--app-border) !important;
}

.border-end {
  border-right: 1px solid var(--app-border) !important;
}

.border-primary {
  border-color: var(--app-primary) !important;
}

.border-success {
  border-color: var(--app-success) !important;
}

.border-danger {
  border-color: var(--app-danger) !important;
}

.border-warning {
  border-color: var(--app-warning) !important;
}

.border-info {
  border-color: var(--app-info) !important;
}

.border-light {
  border-color: var(--app-border) !important;
}

.border-dark {
  border-color: var(--bs-dark, var(--app-fg)) !important;
}

.rounded {
  border-radius: .375rem !important;
}

.rounded-0 {
  border-radius: 0 !important;
}

.rounded-1 {
  border-radius: .25rem !important;
}

.rounded-2 {
  border-radius: .375rem !important;
}

.rounded-3 {
  border-radius: .5rem !important;
}

.rounded-circle {
  border-radius: 50% !important;
}

.rounded-pill {
  border-radius: 50rem !important;
}

.shadow {
  box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15) !important;
}

.shadow-sm {
  box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075) !important;
}

.shadow-lg {
  box-shadow: 0 1rem 3rem rgba(0, 0, 0, .175) !important;
}

.shadow-none {
  box-shadow: none !important;
}

/* ---- position ---- */
.position-static {
  position: static !important;
}

.position-relative {
  position: relative !important;
}

.position-absolute {
  position: absolute !important;
}

.position-fixed {
  position: fixed !important;
}

.position-sticky {
  position: sticky !important;
}

.top-0 {
  top: 0 !important;
}

.top-50 {
  top: 50% !important;
}

.top-100 {
  top: 100% !important;
}

.bottom-0 {
  bottom: 0 !important;
}

.start-0 {
  left: 0 !important;
}

.end-0 {
  right: 0 !important;
}

.translate-middle {
  transform: translate(-50%, -50%) !important;
}

/* ---- sizing ---- */
.w-25 {
  width: 25% !important;
}

.w-50 {
  width: 50% !important;
}

.w-75 {
  width: 75% !important;
}

.w-100 {
  width: 100% !important;
}

.w-auto {
  width: auto !important;
}

.h-25 {
  height: 25% !important;
}

.h-50 {
  height: 50% !important;
}

.h-75 {
  height: 75% !important;
}

.h-100 {
  height: 100% !important;
}

.h-auto {
  height: auto !important;
}

.mw-100 {
  max-width: 100% !important;
}

.mh-100 {
  max-height: 100% !important;
}

.img-fluid {
  max-width: 100%;
  height: auto;
}

/* ---- list ---- */
.list-unstyled {
  padding-left: 0;
  list-style: none;
}

/* ---- minimal themed components (Fluent ships none of these Bootstrap components) ---- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  color: var(--app-fg);
  background-color: var(--app-surface);
  border: 1px solid var(--app-border);
  border-radius: .5rem;
}

.card-body {
  flex: 1 1 auto;
  padding: 1rem;
}

.card-header {
  padding: .75rem 1rem;
  border-bottom: 1px solid var(--app-border);
  background-color: var(--app-surface-soft);
}

.card-footer {
  padding: .75rem 1rem;
  border-top: 1px solid var(--app-border);
  background-color: var(--app-surface-soft);
}

.card-title {
  margin-bottom: .5rem;
}

.badge {
  display: inline-block;
  padding: .35em .65em;
  font-size: .75em;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  text-align: center;
  white-space: nowrap;
  vertical-align: baseline;
  border-radius: .375rem;
}

.badge.bg-light {
  color: var(--app-fg);
}

/* ---- chip / pill utilities — dark-mode-aware soft tints -----------------
   Use `class="chip chip-primary"` (etc.) in any component.
   These adapt automatically via color-mix so no per-component overrides
   are needed when switching between light / dark Fluent themes.
   Variants: chip-primary  chip-success  chip-danger  chip-warning  chip-neutral
   -------------------------------------------------------------------------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 9999px;
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.4;
  border: 1px solid transparent;
  white-space: nowrap;
}

.chip-primary {
  background: var(--app-primary-soft);
  color: var(--app-primary);
  border-color: var(--app-primary-border);
}

.chip-success {
  background: var(--app-success-soft);
  color: var(--app-success);
  border-color: var(--app-success-border);
}

.chip-danger {
  background: var(--app-danger-soft);
  color: var(--app-danger);
  border-color: var(--app-danger-border);
}

.chip-warning {
  background: var(--app-warning-soft);
  color: var(--app-warning);
  border-color: var(--app-warning-border);
}

.chip-neutral {
  background: var(--bs-secondary-bg, var(--app-surface-hover));
  color: var(--bs-secondary-color, var(--app-muted));
  border-color: var(--app-border);
}

/* ---- soft tinted surface utilities — dark-mode-aware tinted backgrounds ---
   Use on cards, KPI boxes, callout panels, info banners, etc.
   Add `border: 1px solid` (or `border: 1px solid inherit`) to expose the
   border-color. Adapts automatically in light + dark via color-mix tokens.
   Variants: surface-primary  surface-success  surface-danger  surface-warning  surface-neutral
   -------------------------------------------------------------------------- */
.surface-primary {
  background: var(--app-primary-soft);
  border-color: var(--app-primary-border);
  color: var(--app-fg);
}

.surface-success {
  background: var(--app-success-soft);
  border-color: var(--app-success-border);
  color: var(--app-fg);
}

.surface-danger {
  background: var(--app-danger-soft);
  border-color: var(--app-danger-border);
  color: var(--app-fg);
}

.surface-warning {
  background: var(--app-warning-soft);
  border-color: var(--app-warning-border);
  color: var(--app-fg);
}

.surface-neutral {
  background: var(--app-surface-soft);
  border-color: var(--app-border);
  color: var(--app-fg);
}

/* ---- form control baseline -----------------------------------------------
   Plain <input>/<textarea>/<select> elements get body-surface theming so they
   don't flash white in dark Fluent mode. DX-themed inputs are wrapped in
   .dx-* containers with higher-specificity rules that still win; component-
   scoped rules also override as needed (no !important here).
   -------------------------------------------------------------------------- */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
textarea,
select {
  background: var(--app-surface);
  color: var(--app-fg);
  border-color: var(--app-border);
}

/* ---- native <table> reboot (Bootstrap parity for the Fluent themes) -------
   The classic (Bootstrap-based) DX themes ship Bootstrap's Reboot, which makes
   hand-rolled <table>s align correctly: <th> INHERITS its row's alignment
   instead of the browser default `center`, and tables collapse their borders.
   The Fluent themes ship none of this, so the module summary cards that render
   native tables (LeaseUp / Recertification / ReRental / Relocation) get their
   <th> centered — the header text drifts out of line with the left-aligned <td>
   bodies below it, most visibly in wide columns (e.g. "Full Name"). See the
   LeaseUp HOUSEHOLD MEMBERS / INCOME DETAILS cards.

   These rules mirror Bootstrap Reboot so those tables align under Fluent exactly
   as they already do under Office White. text-align uses !important because the
   active theme bundle is injected AFTER the page's component <style> blocks and
   otherwise wins the cascade (which is why each card's own `thead th { text-align
   :left }` is not enough on its own under Fluent). This is safe: DevExpress's own
   grids render their headers as <div>s, not <th>, so they are unaffected, and any
   explicit alignment utility (.text-center/.text-end, also !important) still wins
   over a bare element selector by specificity. Classic themes already do this, so
   behaviour there is unchanged.
   -------------------------------------------------------------------------- */
table {
  border-collapse: collapse;
  caption-side: bottom;
}

th {
  text-align: inherit !important;
  text-align: -webkit-match-parent !important;
}

/* ---- card selected state -------------------------------------------------
   Use `card-selected` alongside any card element for a themed primary-tinted
   selected state. Replaces per-component hardcoded #eff6ff selected backgrounds.
   -------------------------------------------------------------------------- */
.card-selected {
  background: var(--app-primary-soft) !important;
  border-color: var(--bs-primary, var(--app-primary)) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--app-primary) 15%, transparent) !important;
}

/* ---- selected table row --------------------------------------------------
   Use `row-selected` on <tr> (or any row element) for themed selected state.
   Replaces per-component .tic-tr-selected / .ou-row-sel / .ou-ut-row-selected
   hardcoded backgrounds.
   -------------------------------------------------------------------------- */
.row-selected {
  background: var(--app-primary-soft) !important;
}

.row-selected:hover {
  background: var(--app-primary-soft-strong) !important;
}

/* ---- step wizard pill indicators ----------------------------------------
   Use `step-active` / `step-done` on step pill elements in wizard flows.
   Replaces per-component .apl-step-active / .apl-step-done hardcoded tints.
   -------------------------------------------------------------------------- */
.step-active {
  background: var(--app-primary-soft-strong);
  color: var(--app-primary);
}

.step-done {
  background: var(--app-success-soft);
  color: var(--app-success);
}

.btn {
  display: inline-block;
  font-weight: 400;
  line-height: 1.5;
  color: var(--app-fg);
  text-align: center;
  text-decoration: none;
  vertical-align: middle;
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  padding: .375rem .75rem;
  font-size: 1rem;
  border-radius: .375rem;
  background-color: transparent;
  transition: color .15s ease, background-color .15s ease, border-color .15s ease;
}

.btn-sm {
  padding: .25rem .5rem;
  font-size: .875rem;
  border-radius: .25rem;
}

.btn-lg {
  padding: .5rem 1rem;
  font-size: 1.25rem;
  border-radius: .5rem;
}

/* Solid/semantic buttons are forced with the COMPOUND selector + !important on
   purpose. Under Fluent the active theme also defines `.btn-primary` but drives
   it through Bootstrap `--bs-btn-*` vars it never populates, so the fill comes
   out white. That theme rule loads AFTER this file and out-specifies a plain
   class here, so !important is required to win. This is safe for the classic
   themes: each fill resolves through --app-*, which equals that theme's own
   `--bs-*` accent (Office White orange), so classic buttons render the same
   color — only Fluent changes, finally picking up its accent (rose / rust / etc.)
   instead of going blank-white. Only the semantic colors are forced; secondary/
   light/outline stay un-forced so the classic themes keep their neutral styling. */
.btn.btn-primary {
  color: #fff !important;
  background-color: var(--app-primary) !important;
  border-color: var(--app-primary) !important;
}

/* secondary/light/outline are NOT compound-bumped: their --app-* values don't
   necessarily match a classic theme's own secondary/light styling, so leaving
   them single-class lets the classic theme keep its look (and they stay subtly
   neutral under Fluent, which is the intended secondary appearance anyway). */
.btn-secondary {
  color: #fff;
  background-color: var(--app-muted);
  border-color: var(--app-muted);
}

.btn.btn-success {
  color: #fff !important;
  background-color: var(--app-success) !important;
  border-color: var(--app-success) !important;
}

.btn.btn-danger {
  color: #fff !important;
  background-color: var(--app-danger) !important;
  border-color: var(--app-danger) !important;
}

.btn.btn-warning {
  color: #000 !important;
  background-color: var(--app-warning) !important;
  border-color: var(--app-warning) !important;
}

.btn-light {
  color: var(--app-fg);
  background-color: var(--app-surface-soft);
  border-color: var(--app-border);
}

.btn-outline-primary {
  color: var(--app-primary);
  border-color: var(--app-primary);
  background-color: transparent;
}

.btn-outline-secondary {
  color: var(--app-muted);
  border-color: var(--app-border);
  background-color: transparent;
}

.alert {
  position: relative;
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-radius: .375rem;
  color: var(--app-fg);
}

.alert-info {
  background-color: color-mix(in srgb, var(--app-info) 14%, var(--app-surface));
  border-color: var(--app-info);
}

.alert-success {
  background-color: color-mix(in srgb, var(--app-success) 14%, var(--app-surface));
  border-color: var(--app-success);
}

.alert-warning {
  background-color: color-mix(in srgb, var(--app-warning) 16%, var(--app-surface));
  border-color: var(--app-warning);
}

.alert-danger {
  background-color: color-mix(in srgb, var(--app-danger) 14%, var(--app-surface));
  border-color: var(--app-danger);
}

.spinner-border {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  vertical-align: -.125em;
  border: .25em solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: .75s linear infinite app-bridge-spin;
}

.spinner-border-sm {
  width: 1rem;
  height: 1rem;
  border-width: .2em;
}

@keyframes app-bridge-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---- Bootstrap modal parity (Fluent ships no modal component) -------------
   Markup using Bootstrap's modal classes (.modal / .modal-dialog / .modal-
   content / .modal-header|body|footer / .btn-close) renders as a fixed,
   centered popup under the classic (Bootstrap-based) themes. The Fluent themes
   define none of these, so that same markup collapses into the normal document
   flow — e.g. the ApplicationUser "Choose Verification Code Channel" / OTP
   dialogs in SignaturePad.razor appear as an inline grey band instead of a
   popup. These rules mirror Bootstrap 5's modal so the dialog is a real popup
   under Fluent too. Each property is one Bootstrap also sets, so the classic
   themes' own modal CSS (loaded after this file) still wins there — no change
   on classic, parity under Fluent. Colors resolve through the --app-* tokens.
   The trigger markup keeps `style="display:block; background:rgba(0,0,0,.5)"`,
   which supplies the backdrop tint; .modal only needs to fix + size the layer.
   -------------------------------------------------------------------------- */
.modal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1055;
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  outline: 0;
}

.modal-dialog {
  position: relative;
  width: auto;
  margin: .5rem;
  pointer-events: none;
}

.modal-dialog-centered {
  display: flex;
  align-items: center;
  min-height: calc(100% - 1rem);
}

@media (min-width: 576px) {
  .modal-dialog {
    max-width: 500px;
    margin: 1.75rem auto;
  }

  .modal-dialog-centered {
    min-height: calc(100% - 3.5rem);
  }

  .modal-sm {
    max-width: 300px;
  }
}

.modal-content {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  pointer-events: auto;
  color: var(--app-fg);
  background-color: var(--app-surface);
  border: 1px solid var(--app-border);
  border-radius: .5rem;
  outline: 0;
}

.modal-header {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-between;
  padding: 1rem;
  border-bottom: 1px solid var(--app-border);
}

.modal-title {
  margin: 0;
  line-height: 1.5;
  font-size: 1.25rem;
}

.modal-body {
  position: relative;
  flex: 1 1 auto;
  padding: 1rem;
}

.modal-footer {
  display: flex;
  flex-shrink: 0;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: .5rem;
  padding: .75rem 1rem;
  border-top: 1px solid var(--app-border);
}

/* btn-close: theme-aware via mask + currentColor so it stays visible in light
   AND dark Fluent. Under classic themes Bootstrap's own `background` shorthand
   (loaded after) resets background-color to transparent, so only its icon shows
   — the leftover mask clips a transparent box and adds nothing (no double X). */
.btn-close {
  box-sizing: content-box;
  width: 1em;
  height: 1em;
  padding: .25em;
  border: 0;
  border-radius: .375rem;
  background-color: currentColor;
  color: var(--app-fg);
  opacity: .55;
  cursor: pointer;
  -webkit-mask: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
  mask: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;
}

.btn-close:hover {
  opacity: 1;
}

/* ---- Bootstrap form-control / form-select / form-label parity -------------
   Used inside the modals above (and elsewhere). The raw element baseline higher
   up themes bare <input>/<select>; these add the Bootstrap box model so the
   class-based controls look right under Fluent. Classic themes override via
   source order. */
.form-label {
  display: inline-block;
  margin-bottom: .5rem;
}

.form-control,
.form-select {
  display: block;
  width: 100%;
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--app-fg);
  background-color: var(--app-surface);
  border: 1px solid var(--app-border);
  border-radius: .375rem;
}

.form-select {
  padding-right: 2.25rem;
}

.form-control:focus,
.form-select:focus {
  outline: 0;
  border-color: var(--app-primary);
  box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--app-primary) 25%, transparent);
}
