/* NexerIQ theme profile: maps the --nexeriq-* tokens onto Bootstrap 5.3 (NEXER-1248, decision L2).
 *
 * Load order: Velex app.min.css (the DevExpress BootstrapExternal theme), theme-profile-bridge.css,
 * nexeriq-tokens.css, then this file. AppShellAssets does that when a host passes
 * NexerIQThemeProfile.StylesheetPaths as ThemeProfileStylesheetPaths. Without the tokens file every
 * value below is invalid, so never link this file alone.
 *
 * The --bs-* values here are what DevExpress's bootstrap-external.bs5 stylesheet and the Velex rules
 * read. The bridge derives the shades this file does not set (every *-border-subtle, and the
 * secondary, light, dark, warning and info *-text-emphasis) from the mapped base colours, and
 * reconnects the button, check, pagination and active-state variables Bootstrap compiles as literals.
 * The only DevExpress internals set are --dxbl-btn-color and --dxbl-btn-focus-color on primary
 * outline and text buttons, so that in Dark their text can differ from their fill (see below).
 *
 * Status colours (success, danger, warning, info) read only the fixed status tokens and on-status,
 * never a brand token. A test fails the build if one of them does.
 *
 * The mapping is declared on :root and on every [data-bs-theme] element, so a nested themed block
 * resolves its own tokens. It sits at the same specificity as a host profile's documented
 * :root, [data-bs-theme="light"] selectors, so a host file loaded later can still refine a --bs-*
 * variable. The exception is the second block: the variables Velex's
 * [data-bs-theme=dark], html[data-bs-theme=dark] block sets (0,1,1) need :root[data-bs-theme] (0,2,0)
 * to win, which also puts them out of a later host file's reach. Refine those, and preferably every
 * colour, through the --nexeriq-* tokens instead. */

:root,
[data-bs-theme] {
    /* Brand primary */
    --bs-primary: var(--nexeriq-primary);
    --bs-primary-rgb: var(--nexeriq-primary-rgb);
    --bs-primary-text-emphasis: var(--nexeriq-primary-text);
    --bs-primary-bg-subtle: var(--nexeriq-primary-subtle);
    --bs-link-color: var(--nexeriq-link);
    --bs-link-color-rgb: var(--nexeriq-link-rgb);
    --bs-link-hover-color: var(--nexeriq-primary-text);
    --bs-link-hover-color-rgb: var(--nexeriq-primary-text-rgb);
    --bs-focus-ring-color: color-mix(in srgb, var(--nexeriq-focus) 25%, transparent);
    --app-theme-primary-contrast: var(--nexeriq-on-primary);

    /* Neutrals: page, surfaces, text and borders */
    --bs-body-bg: var(--nexeriq-bg);
    --bs-body-bg-rgb: var(--nexeriq-bg-rgb);
    --bs-body-color: var(--nexeriq-text);
    --bs-body-color-rgb: var(--nexeriq-text-rgb);
    --bs-emphasis-color: var(--nexeriq-text);
    --bs-emphasis-color-rgb: var(--nexeriq-text-rgb);
    --bs-heading-color: var(--nexeriq-text);
    --bs-secondary-color: var(--nexeriq-muted);
    --bs-secondary-color-rgb: var(--nexeriq-muted-rgb);
    --bs-secondary-bg: var(--nexeriq-surface);
    --bs-secondary-bg-rgb: var(--nexeriq-surface-rgb);
    --bs-tertiary-color: var(--nexeriq-text-secondary);
    --bs-tertiary-color-rgb: var(--nexeriq-text-secondary-rgb);
    --bs-tertiary-bg: var(--nexeriq-surface-subtle);
    --bs-tertiary-bg-rgb: var(--nexeriq-surface-subtle-rgb);

    /* Neutral theme colours: Secondary is the second button colour (L7). */
    --bs-secondary: var(--nexeriq-muted);
    --bs-secondary-rgb: var(--nexeriq-muted-rgb);
    --app-theme-secondary-contrast: var(--nexeriq-surface);
    --app-theme-light-contrast: var(--nexeriq-text);
    --app-theme-dark-contrast: var(--nexeriq-surface);

    /* Status: fixed status tokens only */
    --bs-success: var(--nexeriq-success);
    --bs-success-rgb: var(--nexeriq-success-rgb);
    --bs-success-text-emphasis: var(--nexeriq-success-text);
    --bs-success-bg-subtle: var(--nexeriq-success-subtle);
    --app-theme-success-contrast: var(--nexeriq-on-status);
    --bs-danger: var(--nexeriq-danger);
    --bs-danger-rgb: var(--nexeriq-danger-rgb);
    --bs-danger-text-emphasis: var(--nexeriq-danger-text);
    --bs-danger-bg-subtle: var(--nexeriq-danger-subtle);
    --app-theme-danger-contrast: var(--nexeriq-on-status);
    --bs-warning: var(--nexeriq-warning);
    --bs-warning-rgb: var(--nexeriq-warning-rgb);
    --bs-warning-bg-subtle: var(--nexeriq-warning-subtle);
    --app-theme-warning-contrast: var(--nexeriq-on-status);
    --bs-info: var(--nexeriq-info);
    --bs-info-rgb: var(--nexeriq-info-rgb);
    --bs-info-bg-subtle: var(--nexeriq-info-subtle);
    --app-theme-info-contrast: var(--nexeriq-on-status);
    --bs-form-valid-color: var(--nexeriq-success-text);
    --bs-form-valid-border-color: var(--nexeriq-success);
    --bs-form-invalid-color: var(--nexeriq-danger-text);
    --bs-form-invalid-border-color: var(--nexeriq-danger);

    /* Shape and type. Line height and control heights stay tokens for the components to adopt;
       changing them here would move every grid row and editor at once. */
    --bs-border-radius-sm: var(--nexeriq-radius-sm);
    --bs-border-radius: var(--nexeriq-radius-md);
    --bs-border-radius-lg: var(--nexeriq-radius-lg);
    --bs-font-sans-serif: var(--nexeriq-font-sans);
    --bs-body-font-size: var(--nexeriq-type-body-size);
}

/* Exactly the variables Velex's dark block sets; a test keeps the two lists equal. */
:root,
:root[data-bs-theme],
[data-bs-theme] {
    --bs-border-color: var(--nexeriq-border);
    --bs-input-border-color: var(--nexeriq-border-strong);
    --bs-input-focus-border-color: var(--nexeriq-focus);
    --bs-headings-color: var(--nexeriq-text);
    --bs-light: var(--nexeriq-surface-subtle);
    --bs-light-rgb: var(--nexeriq-surface-subtle-rgb);
    --bs-dark: var(--nexeriq-text);
    --bs-dark-rgb: var(--nexeriq-text-rgb);
}

/* Primary as text. #2563eb carries white text at 5.2:1 as a fill, but as text it is 3.4:1 on the dark
   surface and 3.7:1 on the dark page. In Dark the text uses therefore read the lighter link token
   (#60a5fa: 7.0:1 on surface, 7.5:1 on bg) and the fills keep --bs-primary. --bs-link-color,
   --bs-link-hover-color and --bs-primary-text-emphasis already read link and primary-text above.
   The variable is set on dark blocks only and reset on light ones, so in Light every rule below falls
   back to --bs-primary resolved on the element itself, exactly as Velex does, and a nested light
   block inside a dark page gets the Light behaviour. */
[data-bs-theme="dark"] {
    --app-theme-primary-text: var(--nexeriq-link);
    --app-theme-primary-text-rgb: var(--nexeriq-link-rgb);
    --app-theme-primary-text-hover: var(--nexeriq-primary-text);
    --app-theme-primary-text-hover-rgb: var(--nexeriq-primary-text-rgb);
}

[data-bs-theme="light"] {
    --app-theme-primary-text: initial;
    --app-theme-primary-text-rgb: initial;
    --app-theme-primary-text-hover: initial;
    --app-theme-primary-text-hover-rgb: initial;
}

.text-primary { color: rgba(var(--app-theme-primary-text-rgb, var(--bs-primary-rgb, 37, 99, 235)), var(--bs-text-opacity, 1)) !important; }
.badge-soft-primary,
.badge-outline-primary { --bs-badge-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb)); }
.nav-tabs { --bs-nav-tabs-link-active-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb)); }

/* Bootstrap outline primary buttons (0.13.1). The bridge sets every outline state from --bs-primary; the
   text states (resting and disabled) read the Dark-only variable, and the hover and active fills keep
   on-primary on #2563eb. Same specificity as the bridge's rule, loaded later. */
.btn-outline-primary {
    --bs-btn-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb));
    --bs-btn-disabled-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb));
}

/* .link-primary at rest. Velex's own rule reads --bs-primary-rgb with !important, and the text and link
   utilities it declares later win over it on the same element (.link-primary.text-white). This rule must load
   later, so it leaves out every element that carries one of those utilities: there Velex's cascade applies
   unchanged. Each :not() list is the set of .text-* and .link-* classes app.min.css declares after
   .link-primary with that property !important; a test keeps the lists equal. In Light the value is the one
   Velex computes, so Light is unchanged; --bs-primary-rgb itself is not touched, because fills and borders
   on the same element read it. */
.link-primary:not(
    .link-secondary, .link-success, .link-warning, .link-info, .link-danger, .link-purple, .link-pink,
    .link-blue, .link-orange, .link-indigo, .link-red, .link-yellow, .link-green, .link-teal,
    .link-cyan, .link-light, .link-dark, .link-body-emphasis, .text-primary, .text-secondary,
    .text-success, .text-warning, .text-info, .text-danger, .text-purple, .text-pink, .text-blue,
    .text-orange, .text-indigo, .text-red, .text-yellow, .text-green, .text-teal, .text-cyan,
    .text-light, .text-dark, .text-black, .text-white, .text-body, .text-muted, .text-black-50,
    .text-white-50, .text-body-secondary, .text-body-tertiary, .text-body-emphasis, .text-reset,
    .text-primary-emphasis, .text-secondary-emphasis, .text-success-emphasis, .text-info-emphasis,
    .text-warning-emphasis, .text-danger-emphasis, .text-light-emphasis, .text-dark-emphasis) {
    color: rgba(var(--app-theme-primary-text-rgb, var(--bs-primary-rgb, 37, 99, 235)), var(--bs-link-opacity, 1)) !important;
}

.link-primary:not(
    .link-secondary, .link-success, .link-warning, .link-info, .link-danger, .link-purple, .link-pink,
    .link-blue, .link-orange, .link-indigo, .link-red, .link-yellow, .link-green, .link-teal,
    .link-cyan, .link-light, .link-dark, .link-body-emphasis, .link-underline-primary,
    .link-underline-secondary, .link-underline-success, .link-underline-warning, .link-underline-info,
    .link-underline-danger, .link-underline-purple, .link-underline-pink, .link-underline-blue,
    .link-underline-orange, .link-underline-indigo, .link-underline-red, .link-underline-yellow,
    .link-underline-green, .link-underline-teal, .link-underline-cyan, .link-underline-light,
    .link-underline-dark, .link-underline) {
    text-decoration-color: rgba(var(--app-theme-primary-text-rgb, var(--bs-primary-rgb, 37, 99, 235)), var(--bs-link-underline-opacity, 1)) !important;
}

/* The hover of .link-primary and .btn-link, and .list-group-item-primary: Velex restates them with literals
   in its orange (3.7-3.9:1 in Dark). These rules match Velex's selectors and load later; in Dark they read
   the Dark-only variables, and in Light each fallback is the literal Velex sets, so Light is unchanged.
   .btn-link at rest is Velex's grey (5.1:1 in Dark), not primary. */
.link-primary:focus,
.link-primary:hover {
    color: rgba(var(--app-theme-primary-text-hover-rgb, 191, 78, 48), var(--bs-link-opacity, 1)) !important;
    text-decoration-color: rgba(var(--app-theme-primary-text-hover-rgb, 191, 78, 48), var(--bs-link-underline-opacity, 1)) !important;
}

.btn-link:hover { color: var(--app-theme-primary-text-hover, #bf4e30); }

.list-group-item-primary { color: var(--app-theme-primary-text, #d65736); }

/* DevExpress primary outline and text buttons (and the filter builder's group button, which DevExpress
   paints the same way) take their resting and focused text from --bs-primary. Their hover and active
   states are a --bs-primary fill under --bs-white, which the rules further down keep on on-primary. */
.dxbl-btn:is(.dxbl-btn-outline-primary, .dxbl-btn-text-primary),
.dxbl-filter-builder .dxbl-btn.dxbl-filter-builder-node-group-btn:not([disabled]) {
    --dxbl-btn-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb));
    --dxbl-btn-focus-color: var(--app-theme-primary-text, var(--bs-primary, #2563eb));
}

/* Solid fills (AppBadge Solid, AppToast ColorBody). Velex hard-codes their text colour with !important,
   which the profile's darker-text-on-light-fill status colours in dark mode would make unreadable, so
   the foregrounds follow the same contrast tokens as the buttons. */
.text-bg-primary { color: var(--nexeriq-on-primary) !important; }
.text-bg-secondary,
.text-bg-dark { color: var(--nexeriq-surface) !important; }
.text-bg-light { color: var(--nexeriq-text) !important; }
.text-bg-success,
.text-bg-danger,
.text-bg-warning,
.text-bg-info { color: var(--nexeriq-on-status) !important; }

/* The same for solid avatars (AppIconAvatar and AppUserAvatar with Soft=false emit .bg-<colour>.text-white). */
.bg-primary.text-white { color: var(--nexeriq-on-primary) !important; }
.bg-secondary.text-white,
.bg-dark.text-white { color: var(--nexeriq-surface) !important; }
.bg-light.text-white { color: var(--nexeriq-text) !important; }
.bg-success.text-white,
.bg-danger.text-white,
.bg-warning.text-white,
.bg-info.text-white { color: var(--nexeriq-on-status) !important; }

/* DevExpress buttons (AppButton, AppDropdown) take every filled-state foreground from --bs-white, and on
   a button --bs-white is used for nothing else. Restating it on the button element reaches those
   foregrounds without touching DevExpress's internal --dxbl-* variables. Toasts and message boxes are
   left alone: they also use --bs-white as a background. */
:is(.dxbl-btn-primary, .dxbl-btn-outline-primary, .dxbl-btn-text-primary) { --bs-white: var(--nexeriq-on-primary); }
:is(.dxbl-btn-secondary, .dxbl-btn-outline-secondary, .dxbl-btn-text-secondary,
    .dxbl-btn-dark, .dxbl-btn-outline-dark, .dxbl-btn-text-dark) { --bs-white: var(--nexeriq-surface); }
:is(.dxbl-btn-success, .dxbl-btn-outline-success, .dxbl-btn-text-success,
    .dxbl-btn-danger, .dxbl-btn-outline-danger, .dxbl-btn-text-danger,
    .dxbl-btn-warning, .dxbl-btn-outline-warning, .dxbl-btn-text-warning,
    .dxbl-btn-info, .dxbl-btn-outline-info, .dxbl-btn-text-info) { --bs-white: var(--nexeriq-on-status); }

/* Two DevExpress composites give a secondary-classed button a primary fill under --bs-white: the pager's
   active page on hover, and the filter builder's group button on hover and press. */
.dxbl-pager > .dxbl-btn.dxbl-btn-outline-secondary.dxbl-pager-active-page-btn,
.dxbl-filter-builder .dxbl-btn.dxbl-filter-builder-node-group-btn { --bs-white: var(--nexeriq-on-primary); }

/* Velex chrome. The theme writes its orange accent into the navigation variables per menu colour, so
   the brand reaches the sidebar only through the same selectors. Light menu first; the dark-menu rule
   follows so that it wins for html[data-bs-theme=dark][data-menu-color=light]. */
html[data-menu-color="light"] {
    --bs-main-nav-item-hover-color: var(--nexeriq-primary);
    --bs-main-nav-item-hover-bg: color-mix(in srgb, var(--nexeriq-primary) 10%, transparent);
}

html[data-bs-theme="dark"][data-menu-color="light"],
html[data-menu-color="dark"] {
    --bs-main-nav-item-hover-color: color-mix(in srgb, var(--nexeriq-primary) 45%, white);
    --bs-main-nav-item-hover-bg: color-mix(in srgb, var(--nexeriq-primary) 20%, transparent);
}

/* In Dark the sidebar and topbar take the NexerIQ surface instead of Velex's greys, whatever menu or
   topbar colour is chosen. The selectors match Velex's own (0,2,1) and load later. */
html[data-bs-theme="dark"][data-menu-color] {
    --bs-main-nav-bg: var(--nexeriq-surface);
    --bs-main-nav-item-color: var(--nexeriq-muted);
    --bs-main-nav-border-color: var(--nexeriq-border);
}

/* Light topbar: Velex's item colour #707793 is 4.06:1 on its #f2f6f9 bar, under AA for the page title (NEXER-1295).
   Same selector as Velex's own (0,1,1), loaded later; the dark rule below is (0,2,1), so it still wins in Dark,
   and a dark topbar in Light ([data-topbar-color="dark"]) keeps Velex's light text. */
html[data-topbar-color="light"] {
    --bs-topbar-item-color: var(--nexeriq-text-secondary);
}

html[data-bs-theme="dark"][data-topbar-color] {
    --bs-topbar-bg: var(--nexeriq-surface);
    --bs-topbar-item-color: var(--nexeriq-text-secondary);
    --bs-topbar-search-bg: var(--nexeriq-surface-subtle);
}

.topbar .topbar-item .topbar-button.active,
.topbar .topbar-item .topbar-button.show,
.topbar .topbar-item .topbar-button:active,
.topbar .topbar-item .topbar-button:hover {
    color: var(--nexeriq-link);
}

/* A dark topbar (Velex #22282e, or the dark surface) needs the same tint as the dark menu: the link blue
   is 2.9:1 on #22282e in Light. */
html[data-bs-theme="dark"][data-topbar-color="light"] .topbar .topbar-item .topbar-button:is(.active, .show, :active, :hover),
html[data-topbar-color="dark"] .topbar .topbar-item .topbar-button:is(.active, .show, :active, :hover) {
    color: color-mix(in srgb, var(--nexeriq-primary) 45%, white);
}

/* Second-level sidebar links: Velex pads them by a quarter of the item padding (calc(11px * .25) top and bottom),
   so a sub-item is about 21 px high, under the 24 px minimum target of WCAG 2.5.8 (NEXER-1295). Velex already
   lays the link out as a flex row; centring keeps the label in the middle of the taller box. Velex sets neither
   property, so this needs no specificity race. It lives here rather than in the shell stylesheet because the
   shell never renders a sub-nav: the hosts that do hand-write Velex's markup and link this profile. */
.main-nav .sub-navbar-nav .sub-nav-item .sub-nav-link {
    min-height: 24px;
    align-items: center;
}

/* AppNavTabs: Velex underlines the active tab in its orange with !important. */
.nav-tabs li a.active {
    border-bottom-color: var(--nexeriq-primary) !important;
}

.breadcrumb-item > a:hover {
    color: var(--nexeriq-primary-text);
}

.nav-link:focus-visible {
    box-shadow: 0 0 0 0.15rem color-mix(in srgb, var(--nexeriq-focus) 25%, transparent);
}
