@charset "UTF-8";
@import url("open-iconic-bootstrap.min.css");
/* ==========================================================================
  Poppins font weights
  --------------------------------------------------------------------------
  Purpose:
  Registers all local Poppins font files for normal and italic styles so the
  application can use Poppins consistently without relying on external font
  providers.
  ========================================================================== */
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 100;
  src: url("../fonts/poppins/poppins-latin-100-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 100;
  src: url("../fonts/poppins/poppins-latin-100-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 200;
  src: url("../fonts/poppins/poppins-latin-200-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 200;
  src: url("../fonts/poppins/poppins-latin-200-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 300;
  src: url("../fonts/poppins/poppins-latin-300-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 300;
  src: url("../fonts/poppins/poppins-latin-300-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url("../fonts/poppins/poppins-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 400;
  src: url("../fonts/poppins/poppins-latin-400-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 500;
  src: url("../fonts/poppins/poppins-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 500;
  src: url("../fonts/poppins/poppins-latin-500-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 600;
  src: url("../fonts/poppins/poppins-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 600;
  src: url("../fonts/poppins/poppins-latin-600-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url("../fonts/poppins/poppins-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 700;
  src: url("../fonts/poppins/poppins-latin-700-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 800;
  src: url("../fonts/poppins/poppins-latin-800-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 800;
  src: url("../fonts/poppins/poppins-latin-800-italic.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-display: swap;
  font-weight: 900;
  src: url("../fonts/poppins/poppins-latin-900-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins";
  font-style: italic;
  font-display: swap;
  font-weight: 900;
  src: url("../fonts/poppins/poppins-latin-900-italic.woff2") format("woff2");
}
/* ==========================================================================
   Conventus icon font
   --------------------------------------------------------------------------
   Purpose:
   Registers the custom Conventus icon font used by all .conv-* icon classes.
   When updating the icon font files, the codepoints below should be checked
   and updated as well.
   ========================================================================== */
@font-face {
  font-family: "conventus-ivons";
  font-style: normal;
  font-display: block;
  font-weight: normal;
  src: url("../fonts/conventus-ivons.ttf?dnyf2") format("truetype"), url("../fonts/conventus-ivons.woff?dnyf2") format("woff"), url("../fonts/conventus-ivons.svg?dnyf2#conventus-ivons") format("svg");
}
/* ==========================================================================
   Conventus icon base class
   --------------------------------------------------------------------------
   Purpose:
   Applies the custom Conventus icon font to all icon classes that start with
   conv- or contain conv-. The !important prevents browser extensions or global
   font rules from replacing the icon font.
   ========================================================================== */
[class^=conv-],
[class*=" conv-"] {
  font-family: "conventus-ivons" !important;
  font-style: normal;
  font-weight: normal;
  font-variant: normal;
  line-height: 1;
  text-transform: none;
  speak: never;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ==========================================================================
   Conventus icon codepoints
   --------------------------------------------------------------------------
   Purpose:
   Maps each Conventus icon class to the correct glyph inside the custom icon
   font. These values must stay in sync with the generated icon font files.
   ========================================================================== */
.conv-icon-storage::before {
  content: "\e900";
}

.conv-icon-activity::before {
  content: "\e901";
}

.conv-icon-add::before {
  content: "\e902";
}

.conv-icon-add-time::before {
  content: "\e903";
}

.conv-icon-brand::before {
  content: "\e904";
}

.conv-icon-calendar::before {
  content: "\e905";
}

.conv-icon-category::before {
  content: "\e906";
}

.conv-icon-close::before {
  content: "\e907";
}

.conv-icon-components::before {
  content: "\e908";
}

.conv-icon-confirm::before {
  content: "\e909";
}

.conv-icon-contact::before {
  content: "\e90a";
}

.conv-icon-copy::before {
  content: "\e90b";
}

.conv-icon-customers::before {
  content: "\e90c";
}

.conv-icon-dashboard::before {
  content: "\e90d";
}

.conv-icon-delete::before {
  content: "\e90e";
}

.conv-icon-doc-add::before {
  content: "\e90f";
}

.conv-icon-dropdown::before {
  content: "\e910";
}

.conv-icon-edit::before {
  content: "\e911";
}

.conv-icon-equipment::before {
  content: "\e912";
}

.conv-icon-filter::before {
  content: "\e913";
}

.conv-icon-filter-2::before {
  content: "\e914";
}

.conv-icon-gear::before {
  content: "\e915";
}

.conv-icon-gear-2::before {
  content: "\e916";
}

.conv-icon-gear-2-square::before {
  content: "\e917";
}

.conv-icon-hidemenu::before {
  content: "\e918";
}

.conv-icon-invoice::before {
  content: "\e919";
}

.conv-icon-locationpin::before {
  content: "\e91a";
}

.conv-icon-mail::before {
  content: "\e91b";
}

.conv-icon-messages::before {
  content: "\e91c";
}

.conv-icon-notification::before {
  content: "\e91d";
}

.conv-icon-phone::before {
  content: "\e91e";
}

.conv-icon-product::before {
  content: "\e91f";
}

.conv-icon-production-orders::before {
  content: "\e920";
}

.conv-icon-project-2::before {
  content: "\e921";
}

.conv-icon-purchaseorders::before {
  content: "\e922";
}

.conv-icon-quotation::before {
  content: "\e923";
}

.conv-icon-resource::before {
  content: "\e924";
}

.conv-icon-salesorders::before {
  content: "\e925";
}

.conv-icon-search::before {
  content: "\e926";
}

.conv-icon-shipment::before {
  content: "\e927";
}

.conv-icon-stats::before {
  content: "\e928";
}

.conv-icon-sub-category::before {
  content: "\e929";
}

.conv-icon-suppliers::before {
  content: "\e92a";
}

.conv-icon-support::before {
  content: "\e92b";
}

.conv-icon-textsize::before {
  content: "\e92c";
}

.conv-icon-units::before {
  content: "\e92d";
}

.conv-icon-upload::before {
  content: "\e92e";
}

.conv-icon-view-doc::before {
  content: "\e92f";
}

.conv-icon-warehouse::before {
  content: "\e930";
}

.conv-icon-warning::before {
  content: "\e931";
}

.conv-icon-workorder::before {
  content: "\e932";
}

.conv-icon-work-order-template::before {
  content: "\e933";
}

:root {
  --cv-primary: #f07e26;
  --cv-primary-rgb: 240, 126, 38;
  --cv-primary-dark: #ca6510;
  --cv-secondary: #f1f1f1;
  --cv-text-primary: #000000;
  --cv-text-secondary: #7e7e7e;
  --bs-primary: var(--cv-primary);
  --bs-danger-rgb: rgb(232, 17, 35);
  --dxbl-fl-item-spacing-x: 1.25rem;
  --dxbl-fl-item-spacing-y: 0.5rem;
  --grid-out-of-stock: #ff121273;
  --grid-out-of-stock-hover: #ff1212b8;
  --cv-icon-muted: #9c9c9c;
  --cv-icon-muted-dark: #565656;
  --cv-primary-brand: #ba580d;
  --cv-icon-orange: #f47b20;
  --cv-messagebox-btn-primary: #fd7e14;
  --cv-messagebox-btn-secondary-text: #343a40;
  --cv-messagebox-btn-secondary-border: #495057;
  --cv-status-grey: #b9b9b9;
  --cv-status-success: #25b315;
  --cv-status-danger: #c92600;
  --cv-status-warning: #ffa700;
  --cv-status-info: #1560bd;
  --cv-status-dark-blue: #191970;
  --cv-status-yellow: #f6dd29;
  --cv-status-red: #e50000;
  --cv-status-dark-red: #720004;
  --cv-kpi-danger-accent: #e15759;
  --cv-kpi-positive: #28a745;
  --cv-kpi-negative: #dc3545;
  --cv-grid-row-invalid: #e93142;
  --cv-border: #d6d6d6;
  --cv-border-strong: #8f8f8f;
  --cv-border-muted: #b7b7b7;
  --cv-border-panel: #e4e6eb;
  --cv-border-section: #eceef1;
  --cv-border-faint: #f0f1f3;
  --cv-border-input: #ced4da;
  --cv-surface-muted: #eeeeee;
  --cv-surface-subtle: #f8f9fa;
  --cv-surface-icon-bg: #ececec;
  --cv-text-heading: #2f3437;
  --cv-text-dark: #333333;
  --cv-text-muted: #6c757d;
  --cv-text-subtle: #6f6f6f;
  --cv-popover-text: #303030;
  /* Conditional messages (NoticeBanner): a tinted surface with dark, readable text - the same three
     states everywhere, so a warning in a popup reads the same as a warning on a page. */
  --cv-notice-info-bg: #cff4fc;
  --cv-notice-info-border: #b6effb;
  --cv-notice-info-fg: #055160;
  --cv-notice-warning-bg: #fff3cd;
  --cv-notice-warning-border: #ffecb5;
  --cv-notice-warning-fg: #664d03;
  --cv-notice-error-bg: #f8d7da;
  --cv-notice-error-border: #f5c2c7;
  --cv-notice-error-fg: #842029;
}

/* ==========================================================================
   Fluid container reset
   --------------------------------------------------------------------------
   Purpose:
   Removes default Bootstrap container padding so the page content can align
   flush with the surrounding Conventus layout.
   ========================================================================== */
.container-fluid {
  padding: 0 !important;
}

/* ==========================================================================
   Badge base styling
   --------------------------------------------------------------------------
   Purpose:
   Defines compact badge sizing, spacing and border radius for status labels
   and small inline indicators.
   ========================================================================== */
.badge {
  padding: 0.4em 0.65em 0.35em;
  color: inherit;
  font-size: 11px;
  font-weight: 400;
  line-height: 1;
  vertical-align: middle;
  border-radius: 5px;
}

/* ==========================================================================
   Badge color variants
   --------------------------------------------------------------------------
   Purpose:
   Provides Conventus-specific badge color variants for primary, secondary,
   success, danger, warning, info, light and dark states.
   ========================================================================== */
.badge-primary {
  color: #fff !important;
  background-color: var(--cv-primary) !important;
}

.badge-secondary {
  color: #000 !important;
  background-color: var(--cv-status-grey) !important;
}

.badge-success {
  color: #fff !important;
  background-color: var(--cv-status-success) !important;
}

.badge-danger {
  color: #fff !important;
  background-color: var(--cv-status-danger) !important;
}

.badge-warning {
  color: #000 !important;
  background-color: var(--cv-status-warning) !important;
}

.badge-info {
  color: #fff !important;
  background-color: var(--cv-status-info) !important;
}

.badge-light {
  color: #000 !important;
  background-color: var(--cv-secondary) !important;
}

.badge-dark {
  color: #fff !important;
  background-color: var(--cv-status-dark-blue) !important;
}

/* ==========================================================================
   Conventus theme overwrite variables
   --------------------------------------------------------------------------
   Purpose:
   List of CSS variables that overwrite the default Fluent Theme variables to match
   Conventus design. These are defined as CSS variables here because they are used frequently across the application and defining them as CSS variables
   allows for easier maintenance and potential dynamic theming in the future.
   ========================================================================== */
:root {
  --conventus-primary: var(--cv-primary-brand);
  --conventus-border: var(--cv-border);
  --conventus-font-family: "Poppins", "Helvetica Neue", Arial, sans-serif;
}

/* ==========================================================================
   Theme variables overwrite
   --------------------------------------------------------------------------
   Purpose:
   List of theme variables that are overwritten to match Conventus design.
   ========================================================================== */
:root {
  --bs-primary-rgb: 186, 88, 13;
  --dxbl-text-font-family: var(--conventus-font-family) !important;
  --dxbl-grid-font-family: var(--conventus-font-family) !important;
  --dxds-font-family-sans-serif: var(--conventus-font-family) !important;
  --bs-link-color: #ff6c00;
  --bs-btn-bg: var(--conventus-primary);
  --dxds-color-content-highlight-rest: var(--conventus-primary);
}

/* ==========================================================================
  Conventus Fluent Grid Layer
  --------------------------------------------------------------------------
  Purpose:
  Adds Conventus-specific behavior and layout on top of the DevExpress Fluent
  theme. This file should not replace the Fluent theme; it should be loaded
  after it through ThemeFluentProperties.AddFilePaths(...).
  ========================================================================== */
/* ==========================================================================
   Local CSS variables
   --------------------------------------------------------------------------
   Purpose:
   Centralizes Conventus colors and fallbacks used by the grid overrides.
   Existing app variables such as --cv-primary and --cv-secondary are respected.
   ========================================================================== */
:root {
  --cv-grid-primary: var(--cv-primary, #ba580d);
  --cv-grid-secondary: var(--cv-secondary, #f1f1f1);
  --cv-grid-out-of-stock: var(--grid-out-of-stock, #fff3cd);
  --cv-grid-out-of-stock-hover: var(--grid-out-of-stock-hover, #ffe69c);
  --cv-grid-danger: var(--cv-grid-row-invalid);
  --cv-grid-validation-danger: var(--cv-status-danger);
  --cv-grid-detail-border: var(--cv-border-muted);
  --cv-grid-edit-form-padding: 1.25rem;
  --cv-grid-command-button-padding: 5px;
  --cv-grid-header-indent-radius: 20px;
}

/* ==========================================================================
   Old Conventus grid visual parity layer
   --------------------------------------------------------------------------
   Purpose:
   Restores the most visible differences between the old Office White based
   Conventus grid and the new Fluent grid.
   ========================================================================== */
:root {
  --cv-grid-primary: var(--cv-primary, #ba580d);
  --cv-grid-secondary: var(--cv-secondary, #f1f1f1);
  --cv-grid-header-bg: var(--cv-surface-muted);
  --cv-grid-border: var(--cv-border);
  --cv-grid-border-strong: var(--cv-border-strong);
  --cv-grid-icon-color: var(--cv-icon-orange);
  --cv-grid-text-muted: var(--cv-text-subtle);
}

/* ==========================================================================
   Reusable helpers
   --------------------------------------------------------------------------
   Purpose:
   Keeps repeated border, button and row behavior consistent and easier to
   adjust when DevExpress changes small Fluent details.
   ========================================================================== */
/* ==========================================================================
   Main DxGrid behavior
   --------------------------------------------------------------------------
   Purpose:
   Removes the old heavy theme border, restores row cursor behavior, controls
   table layout, and keeps cell content compact and single-line.
   ========================================================================== */
.dxbl-grid {
  border: none;
}
.dxbl-grid tr td {
  cursor: pointer;
}
.dxbl-grid tr td.dxbl-grid-edit-form {
  cursor: default;
}
.dxbl-grid .dxbl-grid-table {
  border-collapse: collapse;
}
.dxbl-grid .dxbl-grid-table td {
  width: 1rem;
  overflow: hidden;
  white-space: nowrap;
}
.dxbl-grid .dxbl-grid-table th.searchbox-open {
  width: 30rem;
}

/* ==========================================================================
   Grid top panel and search area
   --------------------------------------------------------------------------
   Purpose:
   Restores the Conventus full-width toolbar/search layout inside the DxGrid
   top panel.
   ========================================================================== */
.dxbl-grid .dxbl-grid-top-panel {
  border: none;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container {
  width: 100%;
  margin-left: 0;
  padding: 15px 0 0.5rem;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group {
  display: flex;
  align-items: center;
  flex-wrap: nowrap !important;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group i {
  margin-right: 0.5rem;
  font-size: 0.85rem;
  color: var(--cv-text-muted);
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group .grid-search {
  border: none;
  padding-left: 0;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group .grid-search .dxbl-text-edit-input,
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group .grid-search input.form-control,
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .input-group .grid-search input {
  padding-left: 0 !important;
  padding-inline-start: 0 !important;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .grid-button {
  white-space: nowrap;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container .grid-button span:not(.dxbl-image) {
  text-decoration: none;
}
.dxbl-grid .dxbl-grid-top-panel .dxbl-grid-search-box-container ::deep .dbl-text-edit:has(:focus)::after {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

/* ==========================================================================
   Grid body rows
   --------------------------------------------------------------------------
   Purpose:
   Restores Conventus row hover, selection, border and spacing behavior while
   still using Fluent as the base grid style.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table > tbody > tr:hover, .dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-selected-row {
  background-color: var(--cv-grid-secondary);
}
.dxbl-grid .dxbl-grid-table > tbody > tr:hover.workplan-out-of-stock, .dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-selected-row.workplan-out-of-stock {
  background-color: var(--cv-grid-out-of-stock-hover);
}
.dxbl-grid .dxbl-grid-table > tbody > tr:hover td, .dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-selected-row td {
  color: var(--dxbl-grid-color, #000) !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr.workplan-out-of-stock {
  background-color: var(--cv-grid-out-of-stock);
}
.dxbl-grid .dxbl-grid-table > tbody > tr.invalid-row {
  color: #fff;
  background-color: var(--cv-grid-danger) !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr td.invalid-cell {
  box-shadow: inset 0 0 0 2px var(--bs-danger) !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr td {
  border-left-width: 0;
  border-bottom-width: 0;
  border-top-width: 1px;
  border-image: none !important;
  border-top-color: var(--cv-grid-secondary);
  border-bottom: 1px solid var(--cv-grid-secondary);
}
.dxbl-grid .dxbl-grid-table > tbody > tr td:first-child {
  position: relative;
  border: none;
  overflow: visible;
  border-top-width: 1px;
  border-top-color: var(--cv-grid-secondary);
  border-bottom: 1px solid var(--cv-grid-secondary);
}
.dxbl-grid .dxbl-grid-table > tbody > tr td:last-child {
  position: relative;
  border: none;
  overflow: visible;
  border-top-width: 1px;
  border-top-color: var(--cv-grid-secondary);
  border-bottom: 1px solid var(--cv-grid-secondary);
}
.dxbl-grid .dxbl-grid-table > tbody > tr td:first-child {
  overflow: hidden;
}
.dxbl-grid .dxbl-grid-table > tbody > tr:nth-last-child(2) td:first-child::before, .dxbl-grid .dxbl-grid-table > tbody > tr:nth-last-child(2) td:last-child::before {
  content: none;
}

/* ==========================================================================
   Keyboard focused row
   --------------------------------------------------------------------------
   Purpose:
   Keyboard Up/Down navigation highlights the focused row. The default theme
   accent is far too bright and hides the command-column icons, so tone it down
   to a subtle tint, clear the cell overlay, and mark the row with a thin accent
   bar. Excludes the selected row so an explicit selection keeps its own style.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-selected-row) {
  background-color: var(--cv-grid-secondary) !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-selected-row) > td {
  color: var(--dxbl-grid-color, #000) !important;
  background-color: transparent !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-selected-row) > td::before {
  background-color: transparent !important;
  border-color: transparent !important;
}
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-selected-row) > td:first-child {
  box-shadow: inset 3px 0 0 0 var(--cv-grid-primary);
}

/* ==========================================================================
   Focused row check box cell
   --------------------------------------------------------------------------
   Purpose:
   A Boolean column renders its cell as a display-view check box that takes its
   border and its tick color from theme variables. On the focused row the theme
   repoints both at its "on surface" colors - white - because its own focused
   row is filled with the accent color. The block above tints that row light
   grey instead, so the resting colors have to be handed back here.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-touch-selection):not(.dxbl-grid-touch-selection-edge) .dxbl-checkbox.dxbl-checkbox-display-view-checked,
.dxbl-grid .dxbl-grid-table > tbody > tr.dxbl-grid-focused-row:not(.dxbl-grid-touch-selection):not(.dxbl-grid-touch-selection-edge) .dxbl-checkbox.dxbl-checkbox-display-view-indeterminate {
  --dxbl-checkbox-primary-checked-check-element-bg: var(--dxds-color-content-primary-compound-rest);
  --dxbl-checkbox-primary-checked-readonly-check-element-border: var(--dxds-color-border-neutral-default-disabled);
}

/* ==========================================================================
   Edit form row
   --------------------------------------------------------------------------
   Purpose:
   Restores the Conventus inline edit area: secondary background, generous
   padding and clear validation-message styling.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table > tbody > tr td.dxbl-grid-edit-form {
  padding: var(--cv-grid-edit-form-padding);
  background: var(--cv-grid-secondary);
  border-bottom: 2px solid #fff;
}
.dxbl-grid .dxbl-grid-table > tbody > tr td.dxbl-grid-edit-form::before {
  bottom: -4px;
  width: calc(100% - 2.5rem);
}

/* ==========================================================================
   Inline edit cell alignment
   --------------------------------------------------------------------------
   Purpose:
   A column with TextAlignment="GridTextAlignment.Right" renders its cells as
   td.dxbl-align-right, and DevExpress keeps that class on the cell in inline
   edit mode. Its own auto-generated editor repeats the class on the <input>,
   but an editor supplied through DataColumnCellEditTemplate does not, so its
   text falls back to the left and amounts visibly jump while a row is edited.
   Re-align the editor input for every right-aligned edit cell. Keyed on the
   cell (data-edit-cell), so filter-row editors and left-aligned columns such
   as text and drop-down fields are untouched.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table td[data-edit-cell].dxbl-align-right .dxbl-text-edit-input {
  text-align: end;
}

/* ==========================================================================
   Read-only grid variants
   --------------------------------------------------------------------------
   Purpose:
   Supports popup/embedded read-only grids with constrained dimensions and a
   stronger selected-row style.
   ========================================================================== */
.readonly-grid {
  width: 1000px;
  max-width: 50dvw;
  height: 400px;
  max-height: 50dvh;
  padding: 10px;
}
.readonly-grid .dxbl-grid {
  max-height: 90%;
}

/* ==========================================================================
   Scroll and virtualization helpers
   --------------------------------------------------------------------------
   Purpose:
   Fixes phantom 1px scrolling caused by sub-pixel rounding in non-virtual
   grids and constrains virtual scrolling grids.
   ========================================================================== */
.dxbl-grid:not(.virtual-scrolling-grid):not(.nested-virtual-scrolling-grid) > .dxbl-scroll-viewer > .dxbl-scroll-viewer-content > .dxbl-grid-table {
  contain: paint;
}

.nested-virtual-scrolling-grid {
  max-height: 300px;
}

.virtual-scrolling-grid {
  height: calc(100dvh - 220px);
}

.gridlayout-content:has(.virtual-scrolling-grid) {
  overflow-y: hidden;
}

/* ==========================================================================
   Grid header and filter row
   --------------------------------------------------------------------------
   Purpose:
   The old grid had a clear grey header band. Fluent is much flatter by
   default, so we explicitly restore the old header/filter visual separation.

   Adds a Bootstrap Icons search icon to input editors inside the DevExpress
   Grid filter row, matching the old Conventus filter styling.

   Removes borders from filter row editors and adds padding to keep the target cell
   ========================================================================== */
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row {
  background-color: var(--cv-grid-header-bg);
  border-bottom: 0;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th.dxbl-grid-header,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th.dxbl-grid-fixed-cell:not(.dxbl-grid-empty-cell) {
  background-color: var(--cv-grid-header-bg);
  border-color: white;
  color: #000;
  font-weight: 600;
  padding-top: 0.55rem;
  padding-bottom: 0.55rem;
  border-width: 2px;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th > .dxbl-grid-header-content > span,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th.dxbl-grid-header > .dxbl-grid-header-content > span,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-header-row > th.dxbl-grid-fixed-cell:not(.dxbl-grid-empty-cell) > .dxbl-grid-header-content > span {
  white-space: nowrap;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row {
  background-color: #fff;
  border-bottom: 2px solid var(--cv-grid-border-strong);
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row .filter-type-container > .element-container {
  flex-grow: 1;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-input-editor::after {
  content: "\f3e1" !important;
  color: var(--cv-icon-muted);
  font-family: bootstrap-icons;
  background: transparent !important;
  display: flex;
  align-items: center;
  margin-right: 0.75rem;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-time-edit,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-edit {
  border: none;
  width: 100%;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-time-edit button,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-edit button {
  border: none;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-time-edit::after,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-date-edit::after {
  display: none !important;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-spinedit {
  border: none;
  width: calc(100% + 15px);
  /* Decrease padding so the targetted border on the TD is not interrupted by this inputs border */
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-spinedit::after {
  display: none !important;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row dxbl-spinedit input {
  padding: 0 1.25rem !important;
}
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row > td,
.dxbl-grid .dxbl-grid-table > thead .dxbl-grid-filter-row > th {
  background-color: #fff;
  border-color: white;
  padding-top: 0.35rem;
  padding-bottom: 0.35rem;
}

/* ==========================================================================
   Command/action icons
   --------------------------------------------------------------------------
   Purpose:
   The old grid used orange action icons. Fluent text buttons default darker,
   so command buttons are recolored back to Conventus orange.
   ========================================================================== */
.dxbl-grid {
  /* The Small/Large cell padding override in _layout.scss widens
     --dxbl-grid-text-cell-padding-x to 1.25rem, and the Fluent theme derives
     the command button horizontal padding from that same variable. The
     action buttons then outgrow the fixed command column width and the last
     icons wrap onto a hidden second line and disappear. Re-pin a compact
     padding on command cells and forbid wrapping so every action icon stays
     visible at all text sizes. */
}
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary {
  color: var(--cv-grid-icon-color);
  background: transparent;
  border: 0;
  box-shadow: none;
}
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn .dxbl-image,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn i,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn [class^=conv-],
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn [class*=" conv-"],
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text .dxbl-image,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text i,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text [class^=conv-],
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text [class*=" conv-"],
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary .dxbl-image,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary i,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary [class^=conv-],
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary [class*=" conv-"] {
  color: var(--cv-grid-icon-color);
}
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn:hover,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text:hover,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary:hover {
  background-color: var(--cv-primary-dark);
}
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn:hover span.dxbl-image,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text:hover span.dxbl-image,
.dxbl-grid .dxbl-grid-command-cell .dxbl-btn.dxbl-btn-text-primary:hover span.dxbl-image {
  color: #fff !important;
}
.dxbl-grid.dxbl-sm .dxbl-grid-command-cell, .dxbl-grid.dxbl-lg .dxbl-grid-command-cell {
  --dxbl-grid-text-cell-padding-x: 0.25rem;
  white-space: nowrap;
}

/* ==========================================================================
   Grid editable status cell
   --------------------------------------------------------------------------
   Purpose:
   Updates the cursor for editable status cells to indicate they are clickable and editable,
   while keeping non-editable status cells with the default cursor.
   This is important for user experience, as it provides a visual cue that the status can be interacted with and changed, which is especially relevant if the status cell uses a custom template that may not have other obvious interactive elements.
   ========================================================================== */
.grid-cell-editable {
  cursor: text !important;
}

/* ==========================================================================
   Inline grid action icon
   --------------------------------------------------------------------------
   Purpose:
   Keeps inline action icons compact, clickable and aligned inside grid cells.
   ========================================================================== */
.grid-inline-action {
  display: inline-flex;
  height: 1.2rem;
  padding: 0 5px;
  margin: 0;
  cursor: pointer !important;
}

/* ==========================================================================
   Grid edited/interactive cell states
   --------------------------------------------------------------------------
   Purpose:
   Highlights modified grid cells and applies pointer cursors to editable
   grid cells.
   ========================================================================== */
.grid-modified-cell {
  background-color: rgba(var(--bs-primary-rgb), 0.15) !important;
}

.grid-cell-editable {
  cursor: pointer !important;
}

/* ==========================================================================
   Grid cell link
   --------------------------------------------------------------------------
   Purpose:
   Provides link-style visual feedback for clickable cell content that
   navigates to a detail page. Shows underline on hover and pointer cursor.
   ========================================================================== */
.grid-cell-link {
  display: block;
  width: 100%;
  height: 100%;
  margin: -0.5rem;
  padding: 0.5rem;
  color: var(--bs-primary);
  text-decoration: none;
  cursor: pointer;
}
.grid-cell-link:hover {
  text-decoration: underline;
  color: var(--bs-primary);
}

/* ==========================================================================
   Grid empty cell fix
   --------------------------------------------------------------------------
   Purpose:
   Sets the empty cells width to 0 to prevent them from taking space.
   Without this fix there would be a row which can't be interacted with and serves no purpose
   ========================================================================== */
.dxbl-grid-empty-cell {
  width: 0 !important;
}

/* ==========================================================================
   Greyed-out grid styling
   --------------------------------------------------------------------------
   Purpose:
   Gives a grid the same background as the grid header and visually greys out
   the body cells. This is useful for grids that should remain visible but look
   inactive, disabled, or read-only.
   ========================================================================== */
.dxbl-grid.greyed-out .dxbl-grid-table {
  background-color: var(--cv-grid-header-bg);
  border-collapse: separate;
}
.dxbl-grid.greyed-out .dxbl-grid-table .dxbl-grid-header {
  border: none;
  border-radius: 0 !important;
}
.dxbl-grid.greyed-out .dxbl-grid-table tbody {
  background-color: var(--cv-grid-header-bg);
}
.dxbl-grid.greyed-out .dxbl-grid-table tbody td {
  background-color: var(--cv-secondary) !important;
  border-radius: 0 !important;
}

/* ==========================================================================
   Grid detail cell
   --------------------------------------------------------------------------
   Purpose:
   Adds a dashed left border and compact padding to detail/expand rows.
   ========================================================================== */
.dxbl-grid .dxbl-grid-table .dxbl-grid-detail-cell {
  padding: 4px 16px;
  border-left: 2px dashed #b7b7b7;
}

/* ==========================================================================
   Grid toolbar dropdown — active option
   --------------------------------------------------------------------------
   Purpose:
   Makes the currently selected option in the grid toolbar submenus
   (text size, edit mode, virtual scrolling) clearly stand out — bold and
   in the Conventus brand color, instead of relying on the check icon alone.
   ========================================================================== */
.grid-buttongroup-button.active {
  font-weight: 600 !important;
  color: var(--cv-grid-primary) !important;
}
.grid-buttongroup-button.active .dxbl-image,
.grid-buttongroup-button.active i {
  color: var(--cv-grid-primary) !important;
}

/* ==========================================================================
   Options menu — on/off toggles
   --------------------------------------------------------------------------
   Purpose:
   The on/off options in the Gantt and swimlane view-options menus carry their
   state in the toggle icon alone (the item text stays unhighlighted), so the
   icon itself is colored: brand color when on, muted when off. Only the icons
   marked with these classes represent state - a plain `bi-toggle-*` icon on an
   either/or option (Show / Hide) is decorative and stays neutral.
   ========================================================================== */
.grid-buttongroup-button .option-toggle-on {
  color: var(--cv-grid-primary) !important;
}
.grid-buttongroup-button .option-toggle-off {
  color: var(--cv-grid-text-muted) !important;
}

/* ==========================================================================
  Header navigation
  --------------------------------------------------------------------------
  Purpose:
  Removes extra padding from the DevExpress menu title and keeps the header
  menu items aligned to the right in a single horizontal row.
  ========================================================================== */
.header-navbar.dxbl-menu-horizontal .dxbl-menu-title {
  padding: 0;
}
.header-navbar .dxbl-menu-item-list {
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-end;
}

/* ==========================================================================
   Main grid layout
   --------------------------------------------------------------------------
   Purpose:
   Ensures the main DevExpress GridLayout fills the available page height while
   preserving the desired horizontal spacing between grid columns.
   Additionally, it hides horizontal overflow on grid layout items to prevent
   unwanted horizontal scrollbars when content exceeds the available width, while
   preserving vertical scrolling for content that exceeds the available height.
   ========================================================================== */
.main-grid {
  /* Scope overflow handling to the content area only. Targeting every grid item (the bare
     .dxbl-gridlayout-item) also clipped the sidebar and header, cutting off the navigation menu. */
}
.main-grid .dxbl-gridlayout-item.content-layout-item {
  overflow-x: hidden;
  overflow-y: auto;
}
.main-grid .dx-gridlayout-root {
  height: auto;
  min-height: 100%;
  grid-column-gap: 1.25rem !important;
}

/* ==========================================================================
   Nested DevExpress FormLayout groups
   --------------------------------------------------------------------------
   Purpose:
   Adjusts nested form layout groups so they look cleaner inside edit/detail
   forms: fixed label width, hidden nested group headers, compact dropdown/edit
   buttons, and Conventus primary coloring for editor icons.
   ========================================================================== */
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col label {
  min-width: 190px;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col {
  margin-top: 0;
  margin-bottom: 0;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-group-header {
  display: none;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col svg .dxbl-image {
  color: red;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn > svg.dxbl-image,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn-group > .dxbl-btn > svg.dxbl-image,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn-group-vertical > .dxbl-btn.dxbl-btn > svg.dxbl-image {
  opacity: 1;
  color: var(--cv-primary);
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn > svg.dxbl-image,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn-group > .dxbl-btn:not(.dxbl-edit-btn-dropdown, .dxbl-btn-outline-secondary) > svg.dxbl-image,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit > .dxbl-btn-group-vertical > .dxbl-btn.dxbl-btn:not(.dxbl-edit-btn-dropdown, .dxbl-btn-outline-secondary) > svg.dxbl-image {
  color: #fff;
  background-color: var(--cv-primary);
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit.dxbl-disabled > .dxbl-btn-group-vertical > .dxbl-btn,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-text-edit.dxbl-disabled > .dxbl-btn-group-right > .dxbl-btn {
  display: none;
}

/* ==========================================================================
   DevExpress tabs
   --------------------------------------------------------------------------
   Purpose:
   Keeps the active tab aligned with the Conventus visual style: active text
   inherits the current theme color and uses a slightly stronger font weight.
   ========================================================================== */
.dxbl-tabs > .dxbl-scroll-viewer > .dxbl-scroll-viewer-content > ul > li > .dxbl-tabs-item:not(.dxbl-tabs-tmpl):not(.dxbl-disabled):not(:disabled).dxbl-active {
  font-weight: 600;
}
.dxbl-tabs > .dxbl-scroll-viewer > .dxbl-scroll-viewer-content > ul > li > .dxbl-tabs-item:not(.dxbl-tabs-tmpl):not(.dxbl-disabled):not(:disabled).dxbl-active .dxbl-text {
  color: inherit;
}
.dxbl-tabs > ul > li > .dxbl-tabs-item:not(.dxbl-tabs-tmpl):not(.dxbl-disabled):not(:disabled).dxbl-active {
  font-weight: 600;
}
.dxbl-tabs > ul > li > .dxbl-tabs-item:not(.dxbl-tabs-tmpl):not(.dxbl-disabled):not(:disabled).dxbl-active .dxbl-text {
  color: inherit;
}

/* ==========================================================================
   DevExpress grid size variants
   --------------------------------------------------------------------------
   Purpose:
   Overrides DevExpress grid cell padding for small and large grid variants so
   both sizes keep the same Conventus spacing.
   ========================================================================== */
.dxbl-grid.dxbl-sm, .dxbl-grid.dxbl-lg {
  --dxbl-grid-text-cell-padding-x: 1.25rem;
  --dxbl-grid-text-cell-padding-y: 0.5rem;
}

/* ==========================================================================
   Disabled editor buttons
   --------------------------------------------------------------------------
   Purpose:
   Hides disabled custom editor buttons inside text editor button groups, while
   keeping clear buttons and icon-only buttons visible.
   ========================================================================== */
.dxbl-text-edit > .dxbl-btn-group > .dxbl-btn:not(.dxbl-btn.dxbl-edit-btn-clear, .dxbl-btn.dxbl-btn-icon).dxbl-disabled, .dxbl-text-edit > .dxbl-btn-group > .dxbl-btn:not(.dxbl-btn.dxbl-edit-btn-clear, .dxbl-btn.dxbl-btn-icon):disabled {
  display: none;
}

/* ==========================================================================
   GridLayout row spacing
   --------------------------------------------------------------------------
   Purpose:
   Adds a fixed 10px vertical gap between rows in DevExpress GridLayout
   instances that opt in with the grid-layout-row-gap-10 class.
   ========================================================================== */
.grid-layout-row-gap-10 dxbl-grid-layout-root {
  row-gap: 10px;
}

/* ==========================================================================
   Bootstrap primary button background
   --------------------------------------------------------------------------
   Purpose:
   Overrides Bootstrap's primary button background variable. This affects
   buttons such as <button class="btn btn-primary">...</button>.
   ========================================================================== */
.btn.btn-primary {
  --bs-btn-bg: var(--cv-primary);
  --bs-btn-border-color: var(--cv-primary);
  --bs-btn-hover-bg: var(--cv-primary-dark);
  --bs-btn-hover-border-color: var(--cv-primary-dark);
  --bs-btn-active-bg: var(--cv-primary-dark);
  --bs-btn-active-border-color: var(--cv-primary-dark);
}

/* ==========================================================================
   Standalone text-primary button color
   --------------------------------------------------------------------------
   Purpose:
   Applies the Conventus orange color to standalone DevExpress text-primary
   buttons, such as icon/action buttons that are not part of a button group.
   ========================================================================== */
.dxbl-btn.dxbl-btn-text-primary.dxbl-btn-standalone {
  color: var(--cv-primary);
}

/* ==========================================================================
   Main button sizing
   --------------------------------------------------------------------------
   Purpose:
   Normalizes the height and padding for primary, secondary and outline
   Secondary DevExpress buttons so normal buttons visually match split buttons.
   Split buttons are left with smaller padding to accommodate the dropdown arrow without increasing the overall button size.

   Excluded:
   Form field buttons such as dropdown or the clear button
   ========================================================================== */
.dxbl-btn.dxbl-btn-primary:not(.dxbl-edit-btn-dropdown):not(.dxbl-edit-btn-clear):not(.dxbl-spin-btn-inc):not(.dxbl-spin-btn-dec), .dxbl-btn.dxbl-btn-secondary:not(.dxbl-edit-btn-dropdown):not(.dxbl-edit-btn-clear):not(.dxbl-spin-btn-inc):not(.dxbl-spin-btn-dec), .dxbl-btn.dxbl-btn-outline-secondary:not(.dxbl-edit-btn-dropdown):not(.dxbl-edit-btn-clear):not(.dxbl-spin-btn-inc):not(.dxbl-spin-btn-dec) {
  height: 2.65em;
  padding: 1rem;
}
.dxbl-btn.dxbl-btn-split-dropdown {
  padding: 0.5rem;
}

/* ==========================================================================
   Secondary button styling
   --------------------------------------------------------------------------
   Purpose:
   Keeps secondary DevExpress buttons flat and neutral: black border, no shadow,
   and white background when active.
   ========================================================================== */
.dxbl-btn.dxbl-btn-secondary {
  --dxbl-btn-border-color: black;
  --dxbl-btn-hover-border-color: black;
  --dxbl-btn-active-bg: #ffffff;
  box-shadow: none;
}

/* ==========================================================================
   Link button underline spacing
   --------------------------------------------------------------------------
   Purpose:
   Improves readability for DevExpress link-style buttons by adding a small
   offset between the text and underline.
   ========================================================================== */
.dxbl-btn.dxbl-btn-link span:not(.dxbl-image), .dxbl-btn.dxbl-btn-outline-link span:not(.dxbl-image), .dxbl-btn.dxbl-btn-text-link span:not(.dxbl-image) {
  text-underline-offset: 2px;
}

/* ==========================================================================
   DevExpress SplitButton dropdown menu
   --------------------------------------------------------------------------
   Purpose:
   Makes SplitButton dropdown menu text darker and removes the large empty
   space around a small menu item list.
   ========================================================================== */
.dxbl-dropdown .dxbl-listbox,
.dxbl-dropdown .dxbl-menu,
.dxbl-dropdown .dxbl-menu-item-list,
.dxbl-popup .dxbl-listbox,
.dxbl-popup .dxbl-menu,
.dxbl-popup .dxbl-menu-item-list {
  min-width: max-content;
  width: max-content;
}
.dxbl-dropdown .dxbl-listbox-item,
.dxbl-dropdown .dxbl-menu-item,
.dxbl-popup .dxbl-listbox-item,
.dxbl-popup .dxbl-menu-item {
  min-height: 32px;
  padding: 6px 14px;
  color: #000;
}
.dxbl-dropdown .dxbl-listbox-item .dxbl-text,
.dxbl-dropdown .dxbl-menu-item .dxbl-text,
.dxbl-popup .dxbl-listbox-item .dxbl-text,
.dxbl-popup .dxbl-menu-item .dxbl-text {
  color: #000;
}

/* ==========================================================================
   DevExpress dropdown minimum width
   --------------------------------------------------------------------------
   Purpose:
   Sets a reasonable minimum width for DevExpress dropdowns sub buttons,
   ensure they have less unused space.
   ========================================================================== */
.dxbl-dropdown > .dxbl-dropdown-dialog,
.dxbl-itemlist-dropdown > .dxbl-dropdown-dialog {
  --dxbl-dropdown-min-width: 10rem;
}

/* ==========================================================================
   DevExpress SplitButton dropdown popup content
   --------------------------------------------------------------------------
   Purpose:
   Reduces unnecessary white space inside the popup/dropdown container itself.
   ========================================================================== */
.dxbl-popup-content,
.dxbl-dropdown-body,
.dxbl-dropdown-content {
  padding: 0;
}
.dxbl-popup-content .dxbl-listbox,
.dxbl-popup-content .dxbl-menu,
.dxbl-dropdown-body .dxbl-listbox,
.dxbl-dropdown-body .dxbl-menu,
.dxbl-dropdown-content .dxbl-listbox,
.dxbl-dropdown-content .dxbl-menu {
  margin: 0;
  padding: 0;
}

/* ==========================================================================
   Disabled SplitButton dropdown items
   --------------------------------------------------------------------------
   Purpose:
   Optional: keeps disabled dropdown items readable. Remove this block if you
   want disabled actions to stay visibly greyed out.
   ========================================================================== */
.dxbl-listbox-item.dxbl-disabled, .dxbl-listbox-item:disabled {
  color: #000;
  opacity: 1;
}
.dxbl-listbox-item.dxbl-disabled .dxbl-text, .dxbl-listbox-item:disabled .dxbl-text {
  color: #000;
  opacity: 1;
}

.dxbl-menu-item.dxbl-disabled, .dxbl-menu-item:disabled {
  color: #000;
  opacity: 1;
}
.dxbl-menu-item.dxbl-disabled .dxbl-text, .dxbl-menu-item:disabled .dxbl-text {
  color: #000;
  opacity: 1;
}

/* ==========================================================================
   Disabled form field behavior
   --------------------------------------------------------------------------
   Purpose:
   Keeps all disabled DevExpress form fields readable and clearly non-editable.
   This removes the faded disabled look, keeps text black, and applies a
   not-allowed cursor to text boxes, dropdowns, combo boxes, date edits,
   spin edits, memo fields, tag boxes and checkboxes.
   ========================================================================== */
.dxbl-fl .dxbl-text-edit.dxbl-disabled, .dxbl-fl .dxbl-text-edit:disabled,
.dxbl-fl .dxbl-combobox.dxbl-disabled,
.dxbl-fl .dxbl-combobox:disabled,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled,
.dxbl-fl .dxbl-dropdown-box:disabled,
.dxbl-fl .dxbl-date-edit.dxbl-disabled,
.dxbl-fl .dxbl-date-edit:disabled,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled,
.dxbl-fl .dxbl-date-time-edit:disabled,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled,
.dxbl-fl .dxbl-spin-edit:disabled,
.dxbl-fl .dxbl-memo.dxbl-disabled,
.dxbl-fl .dxbl-memo:disabled,
.dxbl-fl .dxbl-tag-box.dxbl-disabled,
.dxbl-fl .dxbl-tag-box:disabled,
.dxbl-fl .dxbl-checkbox.dxbl-disabled,
.dxbl-fl .dxbl-checkbox:disabled {
  --dxbl-text-edit-disabled-opacity: 1;
  --dxbl-disabled-opacity: 1;
  color: #000;
  cursor: not-allowed;
  opacity: 1;
}
.dxbl-fl .dxbl-text-edit.dxbl-disabled *, .dxbl-fl .dxbl-text-edit:disabled *,
.dxbl-fl .dxbl-combobox.dxbl-disabled *,
.dxbl-fl .dxbl-combobox:disabled *,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled *,
.dxbl-fl .dxbl-dropdown-box:disabled *,
.dxbl-fl .dxbl-date-edit.dxbl-disabled *,
.dxbl-fl .dxbl-date-edit:disabled *,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled *,
.dxbl-fl .dxbl-date-time-edit:disabled *,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled *,
.dxbl-fl .dxbl-spin-edit:disabled *,
.dxbl-fl .dxbl-memo.dxbl-disabled *,
.dxbl-fl .dxbl-memo:disabled *,
.dxbl-fl .dxbl-tag-box.dxbl-disabled *,
.dxbl-fl .dxbl-tag-box:disabled *,
.dxbl-fl .dxbl-checkbox.dxbl-disabled *,
.dxbl-fl .dxbl-checkbox:disabled * {
  color: #000;
  cursor: not-allowed;
  opacity: 1;
}
.dxbl-fl .dxbl-text-edit.dxbl-disabled input,
.dxbl-fl .dxbl-text-edit.dxbl-disabled textarea,
.dxbl-fl .dxbl-text-edit.dxbl-disabled button,
.dxbl-fl .dxbl-text-edit.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-text-edit.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-text-edit.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-text-edit.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-text-edit.dxbl-disabled .dxbl-image, .dxbl-fl .dxbl-text-edit:disabled input,
.dxbl-fl .dxbl-text-edit:disabled textarea,
.dxbl-fl .dxbl-text-edit:disabled button,
.dxbl-fl .dxbl-text-edit:disabled .dxbl-text,
.dxbl-fl .dxbl-text-edit:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-text-edit:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-text-edit:disabled .dxbl-btn,
.dxbl-fl .dxbl-text-edit:disabled .dxbl-image,
.dxbl-fl .dxbl-combobox.dxbl-disabled input,
.dxbl-fl .dxbl-combobox.dxbl-disabled textarea,
.dxbl-fl .dxbl-combobox.dxbl-disabled button,
.dxbl-fl .dxbl-combobox.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-combobox.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-combobox.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-combobox.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-combobox.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-combobox:disabled input,
.dxbl-fl .dxbl-combobox:disabled textarea,
.dxbl-fl .dxbl-combobox:disabled button,
.dxbl-fl .dxbl-combobox:disabled .dxbl-text,
.dxbl-fl .dxbl-combobox:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-combobox:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-combobox:disabled .dxbl-btn,
.dxbl-fl .dxbl-combobox:disabled .dxbl-image,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled input,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled textarea,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled button,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-dropdown-box:disabled input,
.dxbl-fl .dxbl-dropdown-box:disabled textarea,
.dxbl-fl .dxbl-dropdown-box:disabled button,
.dxbl-fl .dxbl-dropdown-box:disabled .dxbl-text,
.dxbl-fl .dxbl-dropdown-box:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-dropdown-box:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-dropdown-box:disabled .dxbl-btn,
.dxbl-fl .dxbl-dropdown-box:disabled .dxbl-image,
.dxbl-fl .dxbl-date-edit.dxbl-disabled input,
.dxbl-fl .dxbl-date-edit.dxbl-disabled textarea,
.dxbl-fl .dxbl-date-edit.dxbl-disabled button,
.dxbl-fl .dxbl-date-edit.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-date-edit.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-date-edit.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-date-edit.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-date-edit.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-date-edit:disabled input,
.dxbl-fl .dxbl-date-edit:disabled textarea,
.dxbl-fl .dxbl-date-edit:disabled button,
.dxbl-fl .dxbl-date-edit:disabled .dxbl-text,
.dxbl-fl .dxbl-date-edit:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-date-edit:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-date-edit:disabled .dxbl-btn,
.dxbl-fl .dxbl-date-edit:disabled .dxbl-image,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled input,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled textarea,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled button,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-date-time-edit:disabled input,
.dxbl-fl .dxbl-date-time-edit:disabled textarea,
.dxbl-fl .dxbl-date-time-edit:disabled button,
.dxbl-fl .dxbl-date-time-edit:disabled .dxbl-text,
.dxbl-fl .dxbl-date-time-edit:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-date-time-edit:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-date-time-edit:disabled .dxbl-btn,
.dxbl-fl .dxbl-date-time-edit:disabled .dxbl-image,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled input,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled textarea,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled button,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-spin-edit:disabled input,
.dxbl-fl .dxbl-spin-edit:disabled textarea,
.dxbl-fl .dxbl-spin-edit:disabled button,
.dxbl-fl .dxbl-spin-edit:disabled .dxbl-text,
.dxbl-fl .dxbl-spin-edit:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-spin-edit:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-spin-edit:disabled .dxbl-btn,
.dxbl-fl .dxbl-spin-edit:disabled .dxbl-image,
.dxbl-fl .dxbl-memo.dxbl-disabled input,
.dxbl-fl .dxbl-memo.dxbl-disabled textarea,
.dxbl-fl .dxbl-memo.dxbl-disabled button,
.dxbl-fl .dxbl-memo.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-memo.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-memo.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-memo.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-memo.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-memo:disabled input,
.dxbl-fl .dxbl-memo:disabled textarea,
.dxbl-fl .dxbl-memo:disabled button,
.dxbl-fl .dxbl-memo:disabled .dxbl-text,
.dxbl-fl .dxbl-memo:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-memo:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-memo:disabled .dxbl-btn,
.dxbl-fl .dxbl-memo:disabled .dxbl-image,
.dxbl-fl .dxbl-tag-box.dxbl-disabled input,
.dxbl-fl .dxbl-tag-box.dxbl-disabled textarea,
.dxbl-fl .dxbl-tag-box.dxbl-disabled button,
.dxbl-fl .dxbl-tag-box.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-tag-box.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-tag-box.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-tag-box.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-tag-box.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-tag-box:disabled input,
.dxbl-fl .dxbl-tag-box:disabled textarea,
.dxbl-fl .dxbl-tag-box:disabled button,
.dxbl-fl .dxbl-tag-box:disabled .dxbl-text,
.dxbl-fl .dxbl-tag-box:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-tag-box:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-tag-box:disabled .dxbl-btn,
.dxbl-fl .dxbl-tag-box:disabled .dxbl-image,
.dxbl-fl .dxbl-checkbox.dxbl-disabled input,
.dxbl-fl .dxbl-checkbox.dxbl-disabled textarea,
.dxbl-fl .dxbl-checkbox.dxbl-disabled button,
.dxbl-fl .dxbl-checkbox.dxbl-disabled .dxbl-text,
.dxbl-fl .dxbl-checkbox.dxbl-disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-checkbox.dxbl-disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-checkbox.dxbl-disabled .dxbl-btn,
.dxbl-fl .dxbl-checkbox.dxbl-disabled .dxbl-image,
.dxbl-fl .dxbl-checkbox:disabled input,
.dxbl-fl .dxbl-checkbox:disabled textarea,
.dxbl-fl .dxbl-checkbox:disabled button,
.dxbl-fl .dxbl-checkbox:disabled .dxbl-text,
.dxbl-fl .dxbl-checkbox:disabled .dxbl-text-edit-input,
.dxbl-fl .dxbl-checkbox:disabled .dxbl-text-edit-template,
.dxbl-fl .dxbl-checkbox:disabled .dxbl-btn,
.dxbl-fl .dxbl-checkbox:disabled .dxbl-image {
  color: #000;
  cursor: not-allowed;
  opacity: 1;
}
.dxbl-fl .dxbl-text-edit.dxbl-disabled svg, .dxbl-fl .dxbl-text-edit:disabled svg,
.dxbl-fl .dxbl-combobox.dxbl-disabled svg,
.dxbl-fl .dxbl-combobox:disabled svg,
.dxbl-fl .dxbl-dropdown-box.dxbl-disabled svg,
.dxbl-fl .dxbl-dropdown-box:disabled svg,
.dxbl-fl .dxbl-date-edit.dxbl-disabled svg,
.dxbl-fl .dxbl-date-edit:disabled svg,
.dxbl-fl .dxbl-date-time-edit.dxbl-disabled svg,
.dxbl-fl .dxbl-date-time-edit:disabled svg,
.dxbl-fl .dxbl-spin-edit.dxbl-disabled svg,
.dxbl-fl .dxbl-spin-edit:disabled svg,
.dxbl-fl .dxbl-memo.dxbl-disabled svg,
.dxbl-fl .dxbl-memo:disabled svg,
.dxbl-fl .dxbl-tag-box.dxbl-disabled svg,
.dxbl-fl .dxbl-tag-box:disabled svg,
.dxbl-fl .dxbl-checkbox.dxbl-disabled svg,
.dxbl-fl .dxbl-checkbox:disabled svg {
  color: var(--cv-icon-muted);
  fill: var(--cv-icon-muted);
}

/* ==========================================================================
   DevExpress group headers and bodies
   --------------------------------------------------------------------------
   Purpose:
   Makes group headers more compact and bold, and reduces group body padding
   for denser Conventus form layouts.
   ========================================================================== */
.dxbl-group > .dxbl-group-header {
  padding: 4px 8px 0;
}
.dxbl-group > .dxbl-group-header > .dxbl-text {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.5rem;
  margin-top: 0.5rem;
  margin-left: 0.65rem;
}

.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body > .dxbl-group-body-content {
  padding: 8px 15px;
}

/* ==========================================================================
   FormLayout group spacing
   --------------------------------------------------------------------------
   Purpose:
   Reduces the default vertical spacing between FormLayout groups for a denser
   Conventus form layout.
   ========================================================================== */
.dxbl-fl .dxbl-fl-gd,
.dxbl-fl .dxbl-fl-gt {
  margin-bottom: calc(var(--dxbl-fl-group-spacing-y) * 0.1);
}

/* ==========================================================================
   Checkbox alignment
   --------------------------------------------------------------------------
   Purpose:
   Vertically centers DevExpress checkbox content.
   ========================================================================== */
.dxbl-checkbox {
  padding-left: 0;
  align-items: center;
}
.dxbl-checkbox > .dxbl-checkbox-check-element {
  width: 1.125rem;
  height: 1.125rem;
}
.dxbl-checkbox.dxbl-checkbox-unchecked > .dxbl-checkbox-check-element {
  background: white;
  border: 2px solid rgba(118, 118, 118, 0.3);
}
.dxbl-checkbox.dxbl-checkbox-checked.dxbl-readonly > .dxbl-checkbox-check-element {
  background: white;
  border: 2px solid rgba(118, 118, 118, 0.3);
}
.dxbl-checkbox.dxbl-checkbox-checked.dxbl-disabled > .dxbl-checkbox-check-element {
  background-color: black;
  opacity: 0.3;
}

/* ==========================================================================
   FormLayout captions
   --------------------------------------------------------------------------
   Purpose:
   Adds a small top margin to columns and gives form captions a medium font
   weight with compact vertical padding.
   ========================================================================== */
.dxbl-col {
  margin-top: 0.5rem;
}

.dxbl-fl:not(.dxbl-fl-calc) .dxbl-fl-item > .dxbl-fl-cpt {
  padding: 1px 0;
  font-weight: 500;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col label {
  padding: 1px 0;
  font-weight: 500;
}

/* ==========================================================================
   Grid edit form caption clipping (Large text size)
   --------------------------------------------------------------------------
   Purpose:
   Prevents form captions from being clipped at the top inside grid edit forms.
   The DevExpress FormLayout (.dxbl-fl) sets overflow:hidden. Its first .dxbl-row
   uses a fixed negative top margin (in px) to offset the row gutter, but our
   .dxbl-col top margin is rem-based (see "FormLayout captions" above), so it
   scales down with the Large text size and no longer fully cancels that pull.
   The first caption row then sits above the FormLayout content box and its top
   gets cut off, dropping the top of words like "Naam" and "Omschrijving".
   Zeroing the first row's negative margin in Large mode (.dxbl-lg) keeps the
   row inside the clipping box without changing Normal/Small layouts.
   ========================================================================== */
.dxbl-grid-edit-form .dxbl-fl.dxbl-lg > .dxbl-row:first-child {
  margin-top: 0;
}

/* ==========================================================================
   Editor input padding
   --------------------------------------------------------------------------
   Purpose:
   Normalizes left padding for text editors and TagBox tags so editor content
   aligns consistently across controls.
   ========================================================================== */
.dxbl-tag-box > .dxbl-tag {
  padding-left: 8px;
}

.dxbl-text-edit > .dxbl-text-edit-template,
.dxbl-text-edit > .dxbl-text-edit-input,
.dxbl-text-edit > textarea {
  padding-left: 8px;
}
.dxbl-text-edit > .dxbl-text-edit-template .dxbl-text-edit-input {
  padding-left: 8px;
}

/* ==========================================================================
   Validation messages
   --------------------------------------------------------------------------
   Purpose:
   Styles validation errors consistently and renders grouped validation
   messages as a custom bullet list without relying on native list styling.
   ========================================================================== */
.validation-message {
  color: var(--bs-danger-rgb);
}

.validation-error-group {
  padding-left: 1rem;
  margin-top: 0;
  margin-bottom: 1rem;
  list-style-type: none;
}
.validation-error-group .validation-message {
  position: relative;
  padding-left: 1rem;
  color: var(--bs-danger-rgb);
}
.validation-error-group .validation-message::before {
  content: "•";
  position: absolute;
  top: -0.3rem;
  left: -0.05rem;
  font-size: 1.4rem;
}

/* ==========================================================================
   Editor validation status spacing
   --------------------------------------------------------------------------
   Purpose:
   Adds spacing before the DevExpress validation icon/status element.
   ========================================================================== */
.dxbl-edit-validation-status {
  padding-left: 6px !important;
}

/* ==========================================================================
   FormLayout group card background
   --------------------------------------------------------------------------
   Purpose:
   Restores the old Conventus FormLayout group styling that existed in the
   Office White based theme: grey group background, rounded corners, no visible
   border, and consistent inner padding for grouped form sections.
   ========================================================================== */
.dxbl-fl .dxbl-fl-group > .dxbl-group,
.dxbl-fl .dxbl-fl-group > dxbl-group-control,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group {
  overflow: hidden;
  color: #000;
  background-color: var(--cv-secondary);
  border: 0;
  border-radius: 20px;
  box-shadow: none;
}
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-header,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-header,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-header {
  color: #000;
  background-color: var(--cv-secondary);
  border: 0;
}
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body {
  background-color: var(--cv-secondary);
}
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body > dxbl-group-body-content {
  padding: 1.25rem;
  background-color: var(--cv-secondary);
}
.dxbl-fl .dxbl-fl-group > .dxbl-group .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group .dxbl-group-body-content {
  background-color: var(--cv-secondary);
}

/* ==========================================================================
   FormLayout group spacing
   --------------------------------------------------------------------------
   Purpose:
   Recreates the old spacing between grouped form sections without adding a
   large gap inside the grey group card itself.
   ========================================================================== */
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd, .dxbl-fl .dxbl-fl-group.dxbl-fl-gt {
  margin: 10px 0 0;
}

/* ==========================================================================
   FormLayout group outer spacing
   --------------------------------------------------------------------------
   Purpose:
   Adds spacing between FormLayout groups while keeping enough room at the top
   of each grey group so labels are not clipped by the rounded container.
   ========================================================================== */
.dxbl-fl > .dxbl-fl-gd,
.dxbl-fl > .dxbl-fl-gt {
  margin: 10px 0 0;
}

/* ==========================================================================
   Nested FormLayout groups
   --------------------------------------------------------------------------
   Purpose:
   Prevents nested groups from creating a second grey rounded card inside an
   existing grey group. This keeps nested groups visually flat and compact.
   ========================================================================== */
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col {
  margin-top: 0.5rem;
  margin-bottom: 0;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group {
  background-color: transparent;
  border: 0;
  border-radius: 0;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > .dxbl-group-header,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > .dxbl-group-header,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > .dxbl-group-header {
  display: none;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > dxbl-group-body,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > dxbl-group-body,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > dxbl-group-body {
  background-color: transparent;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group > dxbl-group-body > dxbl-group-body-content {
  padding: 0;
  background-color: transparent;
}
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > .dxbl-group .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-group-control .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group.dxbl-fl-gd.dxbl-col .dxbl-fl-group.dxbl-fl-gd.dxbl-col > dxbl-form-layout-group .dxbl-group-body-content {
  background-color: transparent;
}

/* ==========================================================================
   CustomForm nested subgroups
   --------------------------------------------------------------------------
   Purpose:
   The "Nested FormLayout groups" rule above hides the header of every nested
   group and zeroes its padding. CustomForm intentionally nests one level of
   captioned subgroups (e.g. Afdichtingen > Bakboord / Midden / Stuurboord), so
   re-show those subgroup captions and restore a little top padding so the
   subgroup header and its first field row are not clipped. The header caption
   text also loses its default left margin so it aligns with the field captions
   below it. Scoped to .customform-layout so other forms keep the flat
   nested-group behaviour.
   ========================================================================== */
.customform-layout .customform-subgroup > .dxbl-group > .dxbl-group-header,
.customform-layout .customform-subgroup > .dxbl-group > dxbl-group-header,
.customform-layout .customform-subgroup > dxbl-group-control > .dxbl-group-header,
.customform-layout .customform-subgroup > dxbl-group-control > dxbl-group-header,
.customform-layout .customform-subgroup > dxbl-form-layout-group > .dxbl-group-header,
.customform-layout .customform-subgroup > dxbl-form-layout-group > dxbl-group-header, .customform-layout .customform-subgroup > .dxbl-group-header,
.customform-layout .customform-subgroup > dxbl-group-header {
  display: flex !important;
  margin-bottom: 0.75rem;
  padding-left: 0;
}
.customform-layout .customform-subgroup > .dxbl-group > .dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > .dxbl-group > .dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > .dxbl-group > dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > .dxbl-group > dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-control > .dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-control > .dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-control > dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-control > dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-form-layout-group > .dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-form-layout-group > .dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-form-layout-group > dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-form-layout-group > dxbl-group-body > dxbl-group-body-content, .customform-layout .customform-subgroup > .dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > .dxbl-group-body > dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-body > .dxbl-group-body-content,
.customform-layout .customform-subgroup > dxbl-group-body > dxbl-group-body-content {
  padding-top: 0.75rem;
}
.customform-layout .customform-subgroup .dxbl-group > .dxbl-group-header > .dxbl-text {
  margin-left: 0;
}

/* ==========================================================================
   CustomForm static label field
   --------------------------------------------------------------------------
   Purpose:
   A 'Label' field type renders static text with no editor. The item keeps a
   (blank) caption row and gives the text the same height as a text editor so
   it lines up row-by-row with input fields placed in an adjacent column.
   ========================================================================== */
.customform-field-label {
  display: flex;
  align-items: center;
  min-height: 2.25rem;
  font-weight: 500;
}

/* ==========================================================================
   FormLayout group inner padding
   --------------------------------------------------------------------------
   Purpose:
   Restores the old Conventus spacing inside FormLayout groups. Without this,
   the Fluent theme places labels and editors too close to the rounded group
   edges, causing the form to look cramped and sometimes visually clipped.
   ========================================================================== */
.dxbl-fl .dxbl-fl-group > .dxbl-group,
.dxbl-fl .dxbl-fl-group > dxbl-group-control,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group {
  padding: 0;
}
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body {
  padding: 0;
  background-color: var(--cv-secondary);
}
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > .dxbl-group > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control > dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > .dxbl-group-body > dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body > .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group > dxbl-group-body > dxbl-group-body-content {
  padding: 1.25rem;
  background-color: var(--cv-secondary);
}
.dxbl-fl .dxbl-fl-group > .dxbl-group .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-group-control .dxbl-group-body-content,
.dxbl-fl .dxbl-fl-group > dxbl-form-layout-group .dxbl-group-body-content {
  padding: 1.25rem;
  background-color: var(--cv-secondary);
}

/* ==========================================================================
   White form background variant
   --------------------------------------------------------------------------
   Purpose:
   Forces selected forms back to a white background when they should not use
   the default grey Conventus FormLayout group styling.
   ========================================================================== */
.form-background-white {
  background: #fff !important;
}
.form-background-white .dxbl-fl-group,
.form-background-white .dxbl-group,
.form-background-white dxbl-group-control,
.form-background-white dxbl-form-layout-group,
.form-background-white .dxbl-group-header,
.form-background-white .dxbl-group-body,
.form-background-white .dxbl-group-body-content {
  background: #fff !important;
}

/* ==========================================================================
   Readonly and disabled editor background
   --------------------------------------------------------------------------
   Purpose:
   Keeps readonly and disabled DevExpress text editors visually white instead
   of greyed out.
   ========================================================================== */
.dxbl-text-edit.dxbl-disabled, .dxbl-text-edit.dxbl-readonly {
  background: #fff;
}

/* ==========================================================================
   Readonly and disabled text editor lock icon
   --------------------------------------------------------------------------
   Purpose:
   Adds a centered Bootstrap Icons lock indicator to disabled/readonly
   DevExpress text editors. The icon is positioned absolutely so it stays
   vertically centered regardless of editor height.
   ========================================================================== */
.dxbl-text-edit.dxbl-disabled, .dxbl-text-edit.dxbl-readonly {
  position: relative;
}
.dxbl-text-edit.dxbl-disabled::after, .dxbl-text-edit.dxbl-readonly::after {
  content: "\f47a" !important;
  position: absolute !important;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  color: var(--cv-icon-muted);
  font-family: bootstrap-icons;
  font-size: 0.85rem;
  line-height: 1;
  background: transparent !important;
  pointer-events: none;
}
.dxbl-text-edit.dxbl-disabled .dxbl-text-edit-input, .dxbl-text-edit.dxbl-readonly .dxbl-text-edit-input {
  padding-right: 1.75rem;
}

/* ==========================================================================
   Disabled checkbox lock icon
   --------------------------------------------------------------------------
   Purpose:
   Adds a Bootstrap Icons lock indicator to disabled checkboxes, using a
   slightly different color because checkbox rendering differs from text edits.
   ========================================================================== */
.dxbl-checkbox.dxbl-disabled::after {
  content: "\f47a" !important;
  position: relative !important;
  color: var(--cv-icon-muted-dark);
  font-family: bootstrap-icons;
  background: transparent !important;
  margin-left: 0.25rem;
}

/* ==========================================================================
   Full-height FormLayout group
   --------------------------------------------------------------------------
   Purpose:
   Forces specific FormLayout groups to fill the available row height.
   ========================================================================== */
.group-height-100 dxbl-group-control {
  height: 100%;
}

/* ==========================================================================
   Form group header decoration reset
   --------------------------------------------------------------------------
   Purpose:
   Removes the dark grey pseudo-element/header bar from DevExpress group
   headers.
   ========================================================================== */
.dxbl-group > .dxbl-group-header::before {
  background-color: transparent !important;
}

/* ==========================================================================
   TimeEdit footer customization
   --------------------------------------------------------------------------
   Purpose:
   Hides the "Now" button in TimeEdit dropdown footers for controls that opt in
   with the timeedit-hide-now class.
   ========================================================================== */
.timeedit-hide-now .dxbl-edit-dropdown-footer > button:first-child {
  display: none;
}

/* ==========================================================================
   Calendar and DateEdit dropdown footer buttons
   --------------------------------------------------------------------------
   Purpose:
   Styles DateEdit/Calendar footer buttons so Apply is primary and Today/Close
   are secondary.
   ========================================================================== */
.dxbl-edit-dropdown-footer > .dxbl-btn:nth-child(2) {
  --dxbl-btn-bg: var(--cv-primary) !important;
  --dxbl-btn-border-color: var(--cv-primary) !important;
  --dxbl-btn-hover-bg: var(--cv-primary) !important;
  --dxbl-btn-hover-border-color: var(--cv-primary) !important;
  --dxbl-btn-active-bg: var(--cv-primary) !important;
  --dxbl-btn-active-border-color: var(--cv-primary) !important;
  --dxbl-btn-color: #ffffff !important;
  color: #fff !important;
}
.dxbl-edit-dropdown-footer > .dxbl-btn:nth-child(1), .dxbl-edit-dropdown-footer > .dxbl-btn:nth-child(3) {
  --dxbl-btn-bg: #ffffff !important;
  --dxbl-btn-border-color: black !important;
  --dxbl-btn-hover-bg: #ffffff !important;
  --dxbl-btn-hover-border-color: black !important;
  --dxbl-btn-active-bg: #ffffff !important;
  --dxbl-btn-color: black !important;
  color: black !important;
}

/* ==========================================================================
   Calendar fixed width
   --------------------------------------------------------------------------
   Purpose:
   Prevents calendar dropdown width changes caused by different month-name
   lengths.
   ========================================================================== */
.dxbl-calendar {
  width: 325px;
}

/* ==========================================================================
   List box height adjustment
   --------------------------------------------------------------------------
   Purpose:
   Sets list boxes to fill the available height of their container, preventing
   awkward empty space when list content is short.
   ========================================================================== */
.dxbl-list-box {
  height: 100%;
}

/* ==========================================================================
   Editor clear button icon contrast
   --------------------------------------------------------------------------
   Purpose:
   Makes the clear/dismiss icon inside DevExpress editors more visible by
   forcing the SVG to a consistent size, circular shape, and white fill/stroke
   color on a filled primary-colour disc. Covers every editor host that exposes
   a clear button so the icon styling stays consistent across the app.

   The primary-colour background lives HERE (not only in the FormLayout rule in
   layout/_layout.scss) because the white fill/stroke is invisible on any white
   surface without it. Editors outside a DxFormLayout - toolbar / filter drop-
   downs such as the Gantt and Capacity planning filters - previously showed a
   white cross on a white field (an invisible clear button users hit by
   accident). Applying the disc globally gives every clear button the same
   white-cross-on-orange look the form editors already had.
   ========================================================================== */
dxbl-tag-box button.dxbl-edit-btn-clear svg.dxbl-image,
dxbl-date-edit button.dxbl-edit-btn-clear svg.dxbl-image,
dxbl-dropdown-box button.dxbl-edit-btn-clear svg.dxbl-image,
dxbl-combo-box button.dxbl-edit-btn-clear svg.dxbl-image,
dxbl-text-box button.dxbl-edit-btn-clear svg.dxbl-image,
dxbl-spin-edit button.dxbl-edit-btn-clear svg.dxbl-image {
  width: 1rem !important;
  height: 1rem !important;
  border-radius: 50%;
  background-color: var(--cv-primary);
  fill: #fff !important;
  stroke: #fff !important;
  stroke-width: 0 !important;
  stroke-linecap: round;
}

/* ==========================================================================
   Input placeholder visibility for disabled editors
   --------------------------------------------------------------------------
   Purpose:
   Hides the placeholder text for disabled input fields
   ========================================================================== */
input:disabled::placeholder {
  color: transparent !important;
}

/* ==========================================================================
   Input required indicator
   --------------------------------------------------------------------------
   Purpose:
   Adds a red mark to the end of form labels for required fields. This is a simple visual
   Helper to easily see what fields are required
   ========================================================================== */
.required-caption:after {
  content: "*";
  color: red;
}

/* ==========================================================================
   Tagbox pill styling
   --------------------------------------------------------------------------
   Purpose:
   Reduces the paddings to the sides and font weight
   ========================================================================== */
dxbl-tag-box .dxbl-tag .dxbl-tag-text {
  font-weight: 400;
  padding-left: 0.125rem !important;
  padding-right: 0.125rem !important;
}

/* ==========================================================================
   Modal vertical alignment
   --------------------------------------------------------------------------
   Purpose:
   Centers modal dialogs vertically inside the modal root container.
   ========================================================================== */
.dxbl-modal > .dxbl-modal-root {
  align-content: center;
}

/* ==========================================================================
   Modal footer button spacing
   --------------------------------------------------------------------------
   Purpose:
   Adds consistent spacing between action buttons in modal footers.
   ========================================================================== */
.dxbl-modal-footer button {
  margin-left: 0.5em;
}

/* ==========================================================================
   Modal close button radius
   --------------------------------------------------------------------------
   Purpose:
   Prevents an oval hover/active shape on the popup close button by forcing a
   small border radius.
   ========================================================================== */
.dxbl-modal > .dxbl-modal-root > .dxbl-popup > .dxbl-modal-content > .dxbl-modal-header .dxbl-popup-header-button {
  --dxbl-btn-border-radius: 5%;
}

/* ==========================================================================
   Modal border reset
   --------------------------------------------------------------------------
   Purpose:
   Removes the default border around DevExpress modal content.
   ========================================================================== */
.dxbl-modal-content {
  border: 0 !important;
}

/* ==========================================================================
   Scrollable popups by default
   --------------------------------------------------------------------------
   Purpose:
   A DevExpress popup grows to fit its content, so a tall one (send document,
   bill of materials, line selection, ...) runs off the bottom of a laptop
   screen and its footer buttons become unreachable without zooming the
   browser out.

   DxPopupBase.Scrollable already solves this, but it defaults to false and
   would have to be repeated on every popup in the app. These two declarations
   are exactly what that property applies (.dxbl-popup-scrollable in the
   DevExpress theme); stating them here without the opt-in class makes a
   scrollable popup the default, new popups included. The body itself already
   carries overflow-y: auto from the theme, so capping the content is what
   actually turns the overflow into a scrollbar; the 3.5rem is the popup's own
   --dxbl-popup-margin, top plus bottom.

   Excluded: drop-down, toolbar and side-panel popups, which reuse the same
   modal markup but bring their own sizing and inner scroll containers, and the
   scheduler appointment form, which renders its own body element and is capped
   in _appointment.scss.

   Per popup opt-out: Scrollable is DevExpress's own switch, so set an explicit
   Height/MaxHeight on the popup rather than fighting this rule.
   ========================================================================== */
.dxbl-modal > .dxbl-modal-root > .dxbl-popup:not(.dxbl-edit-dropdown, .dxbl-btn-dropdown-modal, .dxbl-toolbar-dropdown-modal, .dxbl-toolbar-dialog, .dxbl-toolbar-bottom-sheet, .dxbl-sidepanel-dialog, .dxbl-apt-edit-dialog) > .dxbl-modal-content {
  max-height: calc(100vh - 3.5rem);
  overflow-y: hidden;
}
.dxbl-modal > .dxbl-modal-root > .dxbl-popup:not(.dxbl-edit-dropdown, .dxbl-btn-dropdown-modal, .dxbl-toolbar-dropdown-modal, .dxbl-toolbar-dialog, .dxbl-toolbar-bottom-sheet, .dxbl-sidepanel-dialog, .dxbl-apt-edit-dialog) > .dxbl-modal-content > .dxbl-modal-body {
  overflow-y: auto;
}

/* ==========================================================================
   Create Orders popup scrollbar gutter
   --------------------------------------------------------------------------
   Purpose:
   Reserves the vertical scrollbar gutter inside the Create Orders popup body,
   so content no longer shifts sideways when toggling options makes the
   scrollbar appear or disappear.
   ========================================================================== */
.create-orders-popup .dxbl-modal-body {
  scrollbar-gutter: stable;
}

/* ==========================================================================
   Popover and appointment dialog headers
   --------------------------------------------------------------------------
   Purpose:
   Restores the Conventus orange header styling for popovers and scheduler
   appointment edit dialogs.
   ========================================================================== */
.popover-body {
  color: var(--cv-popover-text);
}

.popover-header,
.dxbl-apt-edit-dialog-header {
  background: var(--cv-primary) !important;
}
.popover-header > div,
.popover-header > .dxbl-btn,
.popover-header > .dxbl-sc-dialog-title,
.popover-header > .dxbl-btn-tool,
.dxbl-apt-edit-dialog-header > div,
.dxbl-apt-edit-dialog-header > .dxbl-btn,
.dxbl-apt-edit-dialog-header > .dxbl-sc-dialog-title,
.dxbl-apt-edit-dialog-header > .dxbl-btn-tool {
  color: #fff !important;
}
.popover-header .dxbl-btn.dxbl-btn-tool:hover,
.dxbl-apt-edit-dialog-header .dxbl-btn.dxbl-btn-tool:hover {
  color: #fff !important;
  background: var(--cv-primary-dark) !important;
  background-color: var(--cv-primary-dark) !important;
  border-color: var(--cv-primary-dark) !important;
}

/* ==========================================================================
   Message box footer buttons
   --------------------------------------------------------------------------
   Purpose:
   Restores Conventus-specific colors for message box primary and secondary
   buttons where DevExpress variables are not enough.
   ========================================================================== */
.dxbl-message-box-footer .dxbl-message-box-footer-primary-button {
  background-color: var(--cv-messagebox-btn-primary) !important;
}
.dxbl-message-box-footer .dxbl-message-box-footer-primary-button:hover {
  color: #fff !important;
  background-color: var(--cv-primary-dark) !important;
  border-color: var(--cv-primary-dark) !important;
}
.dxbl-message-box-footer .dxbl-message-box-footer-secondary-button {
  color: var(--cv-messagebox-btn-secondary-text) !important;
  border-color: var(--cv-messagebox-btn-secondary-border) !important;
}
.dxbl-message-box-footer .dxbl-message-box-footer-secondary-button:hover {
  color: var(--cv-messagebox-btn-secondary-text) !important;
  background-color: var(--cv-surface-subtle) !important;
  border-color: var(--cv-messagebox-btn-secondary-border) !important;
}

/* ==========================================================================
   Status indicator base
   --------------------------------------------------------------------------
   Purpose:
   Defines the shared visual shape for status indicators: a small inline
   circular marker that aligns with surrounding text and leaves space before
   the status label.
   ========================================================================== */
.status-indicator {
  display: inline-block;
  position: relative;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  border-radius: 10px;
  font-style: normal;
  text-align: center;
  vertical-align: middle;
}

/* ==========================================================================
   Hidden status indicator
   --------------------------------------------------------------------------
   Purpose:
   Hides the status indicator completely when no visible status marker should
   be shown.
   ========================================================================== */
.status-none {
  display: none;
}

/* ==========================================================================
   Status wrapper
   --------------------------------------------------------------------------
   Purpose:
   Removes default paragraph spacing around status content so indicators and
   labels align cleanly inside compact layouts such as grids.
   ========================================================================== */
.status-wrapper {
  margin: 0;
}

/* ==========================================================================
   Filled status color variants
   --------------------------------------------------------------------------
   Purpose:
   Provides reusable background and text color combinations for status
   indicators that need a colored circular marker.
   ========================================================================== */
.status-black {
  color: #fff;
  background-color: #000;
}

.status-grey {
  color: #000;
  background-color: var(--cv-status-grey);
}

.status-green {
  color: #fff;
  background-color: var(--cv-status-success);
}

.status-orange {
  color: #000;
  background-color: var(--cv-primary-brand);
}

.status-yellow {
  color: #000;
  background-color: var(--cv-status-yellow);
}

.status-red {
  color: #fff;
  background-color: var(--cv-status-red);
}

.status-dark-red {
  color: #fff;
  background-color: var(--cv-status-dark-red);
}

.status-light-blue {
  color: #fff;
  background-color: var(--cv-status-info);
}

.status-blue {
  color: #fff;
  background-color: var(--cv-status-dark-blue);
}

/* ==========================================================================
   Text-only status color variants
   --------------------------------------------------------------------------
   Purpose:
   Provides reusable text color classes for statuses where only the text should
   be colored and no filled circular marker is needed.
   ========================================================================== */
.status-orange-color {
  color: var(--cv-primary-brand);
}

.status-red-color {
  color: red;
}

/* ==========================================================================
   Readonly status positioning
   --------------------------------------------------------------------------
   Purpose:
   Places the tabs status wrapper in the same position as the edit form status wrapper, so the
   status indicator and label are consistently located across the application regardless of the context.
   ========================================================================== */
.tabs-container .status-wrapper {
  padding: 1rem 1rem 1.25rem 1rem;
  height: 2.65em;
}

/* ==========================================================================
   Main text behavior
   --------------------------------------------------------------------------
   Purpose:
   Overwrites the default text settings of the Fluent Theme to match
   Conventus design. This is required because the old theme set the font
   ========================================================================== */
html,
body {
  font-family: var(--conventus-font-family);
  font-size: var(--conventus-font-size);
  line-height: var(--conventus-line-height);
}
html .bi::before, html [class*=" bi-"]::before,
body .bi::before,
body [class*=" bi-"]::before {
  line-height: inherit;
}

/* ==========================================================================
   Status text styling
   --------------------------------------------------------------------------
   Purpose:
   Highlights warning and danger text with stronger font weight and status
   colors. Also styles urgent Bootstrap icons so they stand out slightly more
   and have spacing before the text.
   ========================================================================== */
.text-danger {
  font-weight: 600;
  color: #C92600 !important;
}

.text-warning {
  font-weight: 600;
  color: #ffa700 !important;
}

.urgent {
  font-weight: 600;
  color: #C92600 !important;
}
.urgent.bi::before {
  margin-right: 5px;
  font-size: 1.2em;
}

/* ==========================================================================
   Scheduler appointment dialog sizing
   --------------------------------------------------------------------------
   Purpose:
   Allows scheduler appointment dialogs that contain work order content to use
   more horizontal space than the default DevExpress modal width, while still
   keeping the dialog within the viewport.
   ========================================================================== */
dxbl-modal-dialog.dxbl-scheduler-color.appointment-with-workorder {
  width: 60vw;
  max-width: 80vw !important;
}

/* ==========================================================================
   Scheduler appointment dialog scrolling
   --------------------------------------------------------------------------
   Purpose:
   The dialog is capped at 90vh (DxSchedulerFormSettings MaxHeight in the
   appointment Overview), but the extended appointment form puts its content in
   its own body element, which carries no overflow of its own. On a laptop
   screen everything past the cap - including the Save button in the form
   footer - was simply clipped, so the only way to reach it was zooming the
   browser out. Cap the form body and let it scroll instead.

   The cap is stated in viewport units rather than left to the dialog's flex
   chain: the extended form nests its body differently per render, so a
   height inherited from the dialog is not reliably definite. 4rem is the
   dialog header (0.6rem padding top/bottom around a 1.4em title), which sits
   outside the scroll area; the slack only makes the dialog end just short of
   its 90vh cap. Keep the two in step if MaxHeight ever changes.
   ========================================================================== */
.dxbl-apt-edit-dialog .dxbl-apt-edit-dialog-body {
  max-height: calc(90vh - 4rem);
  overflow-y: auto;
}

/* ==========================================================================
   Scheduler appointment tooltip header button styling
   --------------------------------------------------------------------------
   Purpose:
   Aligns the tooltip header buttons with the default of the fluent theme
   ========================================================================== */
.dxbl-sc-tooltip-header button {
  color: #000 !important;
}

/* ==========================================================================
   Scheduler appointment dialog header
   --------------------------------------------------------------------------
   Purpose:
   Align the appointment dialog with the rest of the application: replace the
   orange scheduler-themed modal header with the standard white header and a
   dark title, so it matches the other popup dialogs (Edit form, Send quotation).
   ========================================================================== */
.dxbl-apt-edit-dialog-header {
  background-color: #fff !important;
  border-bottom: 1px solid #dee2e6;
}

.popup-header-container .popup-text-header {
  color: #212529 !important;
}
.popup-header-container .popup-close-button {
  color: #6c757d !important;
  background-color: transparent !important;
  border: none !important;
}
.popup-header-container .popup-close-button .dxbl-btn-caption {
  display: none;
}

/* ==========================================================================
   Scheduler appointment tooltip flyout body
   --------------------------------------------------------------------------
   Purpose:
   Restyles the single-click appointment tooltip body (TooltipTemplate.razor)
   to read like the Gantt board flyout card (.gantt-flyout in _gantt.scss): a
   divided header with a work-order icon chip, bold number and a tinted status
   pill, then compact key/value rows and a navigate action under a hairline.
   The DevExpress tooltip frame stays the popover surface, so only the inner
   content is themed here (no competing card background, border or shadow).
   ========================================================================== */
.apt-flyout {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 240px;
  max-width: 360px;
  color: var(--cv-text-primary);
  font-size: 0.8rem;
  line-height: 1.4;
  text-align: left;
}

.apt-flyout-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--cv-border-section);
}

.apt-flyout-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  font-size: 0.85rem;
  background: color-mix(in srgb, var(--cv-primary) 16%, #fff);
  color: var(--cv-primary);
}

.apt-flyout-number {
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--cv-text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.apt-flyout-status {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: auto;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  color: var(--cv-text-secondary);
  color: color-mix(in srgb, var(--apt-status-color, var(--cv-text-secondary)) 72%, #000);
  background: var(--cv-border-section);
  background: color-mix(in srgb, var(--apt-status-color, var(--cv-text-secondary)) 16%, #fff);
}

.apt-flyout-status-dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18);
}

.apt-flyout-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  line-height: 1.45;
}

.apt-flyout-key {
  flex: 0 0 auto;
  color: var(--cv-text-secondary);
  font-weight: 600;
}

.apt-flyout-value {
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
}

.apt-flyout-description {
  color: var(--cv-text-secondary);
  white-space: pre-line;
}

.apt-flyout-actions {
  display: flex;
  padding-top: 0.35rem;
  border-top: 1px solid var(--cv-border-section);
}

.apt-flyout-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--cv-text-muted);
  font-weight: 600;
  font-size: 0.8rem;
  line-height: 1.3;
  cursor: pointer;
}
.apt-flyout-link .conv {
  font-size: 0.9rem;
}
.apt-flyout-link:hover, .apt-flyout-link:focus-visible {
  color: var(--cv-primary);
}

/* ==========================================================================
   File dropzone container
   --------------------------------------------------------------------------
   Purpose:
   Styles the upload dropzone as a fixed-height dashed area with centered
   content, making it visually clear where files can be dropped or selected.
   ========================================================================== */
.file-dropzone {
  display: flex;
  height: 230px;
  margin-top: 20px !important;
  padding: 0 !important;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  border-width: 3px !important;
  border-style: dashed !important;
}
.file-dropzone svg {
  width: 42px;
  height: 42px;
}

/* ==========================================================================
   Placeholder upload image wrapper
   --------------------------------------------------------------------------
   Purpose:
   Centers a placeholder image inside the upload area and keeps the image
   height constrained relative to the viewport width.
   ========================================================================== */
.placeholder-img-upload-wrapper {
  position: relative;
  display: flex;
  height: 15vw;
  align-items: center;
  justify-content: center;
}
.placeholder-img-upload-wrapper img {
  height: 100%;
}

/* ==========================================================================
   Upload button overlay
   --------------------------------------------------------------------------
   Purpose:
   Positions upload buttons above the placeholder image and centers them within
   the upload area. Adds spacing before primary DevExpress buttons.
   ========================================================================== */
.upload-button-wrapper {
  position: absolute;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.upload-button-wrapper .dxbl-btn.dxbl-btn-primary {
  margin-left: 5px;
}

/* ==========================================================================
   Hidden upload panel
   --------------------------------------------------------------------------
   Purpose:
   Hides the DevExpress Upload panel for upload controls that opt in with the
   hide-upload class. This is useful when the upload control is used behind a
   custom dropzone or custom upload UI and the default cancel/progress panel
   should not be visible.
   ========================================================================== */
.hide-upload .dxbl-upload-container .dxbl-upload-panel {
  display: none !important;
}

/* ==========================================================================
   Primary flyout header
   --------------------------------------------------------------------------
   Purpose:
   Applies the Conventus primary color to flyout headers that opt in with the
   background-color-primary class.
   ========================================================================== */
.dxbl-flyout-header.background-color-primary {
  background-color: var(--cv-primary) !important;
}

/* ==========================================================================
   Custom flyout header
   --------------------------------------------------------------------------
   Purpose:
   Styles custom flyout headers with compact padding, white text, a title area
   and right-aligned action buttons.
   ========================================================================== */
.flyout-header {
  padding: 4.6875px 11.25px 4.6875px 5.25px;
  font-weight: 400;
  color: #fff;
  align-content: center;
}
.flyout-header .header-title {
  font-size: 18px;
}
.flyout-header .header-buttons {
  display: flex;
  float: right;
  align-items: center;
  font-size: 13px;
}
.flyout-header .header-buttons .header-close {
  cursor: pointer;
}

/* ==========================================================================
   Flyout button row
   --------------------------------------------------------------------------
   Purpose:
   Aligns flyout footer buttons to the right with consistent spacing and a top
   separator line.
   ========================================================================== */
.flyout-button-row {
  display: flex;
  width: 100%;
  gap: 10px;
  justify-content: flex-end;
  padding-top: 10px;
  border-top: 1px solid var(--cv-text-secondary);
}

/* ==========================================================================
   Dashboard card container
   --------------------------------------------------------------------------
   Purpose:
   Provides a clean white card surface for dashboard widgets, including rounded
   corners, subtle shadow and consistent inner spacing.
   ========================================================================== */
.dashboard-card {
  padding: 1rem;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

/* ==========================================================================
   KPI widget layout
   --------------------------------------------------------------------------
   Purpose:
   Arranges the KPI widget content vertically so the header and KPI cards stack
   cleanly.
   ========================================================================== */
.kpi-widget {
  display: flex;
  flex-direction: column;
}

/* ==========================================================================
   KPI header
   --------------------------------------------------------------------------
   Purpose:
   Adds spacing between the KPI title/header area and the KPI card list below.
   ========================================================================== */
.kpi-header {
  margin-bottom: 0.75rem;
}

/* ==========================================================================
   KPI title
   --------------------------------------------------------------------------
   Purpose:
   Styles the KPI section title with a slightly larger, semibold appearance
   while removing default heading margin.
   ========================================================================== */
.kpi-title {
  margin: 0;
  color: var(--bs-body-color);
  font-size: 1.1rem;
  font-weight: 600;
}

/* ==========================================================================
   KPI card collection
   --------------------------------------------------------------------------
   Purpose:
   Displays KPI cards in a responsive wrapping row with consistent spacing
   between cards.
   ========================================================================== */
.kpi-cards {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-content: flex-start;
}

/* ==========================================================================
   KPI inner card
   --------------------------------------------------------------------------
   Purpose:
   Styles each individual KPI value card with flexible sizing, compact padding,
   a subtle background and a left status border.
   ========================================================================== */
.kpi-inner-card {
  display: flex;
  flex: 1 1 140px;
  flex-direction: column;
  justify-content: center;
  min-width: 140px;
  max-width: 260px;
  padding: 0.75rem 1rem;
  background: var(--bs-tertiary-bg);
  border-left: 4px solid;
  border-radius: 0.375rem;
}
.kpi-inner-card.kpi-inner-card-danger {
  border-left-color: var(--cv-kpi-danger-accent) !important;
}

/* ==========================================================================
   KPI amount
   --------------------------------------------------------------------------
   Purpose:
   Emphasizes the primary KPI value and provides positive/negative color
   variants for financial or performance indicators.
   ========================================================================== */
.kpi-amount {
  color: var(--bs-body-color);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
}
.kpi-amount.kpi-positive {
  color: var(--cv-kpi-positive);
}
.kpi-amount.kpi-negative {
  color: var(--cv-kpi-negative);
}

/* ==========================================================================
   KPI label
   --------------------------------------------------------------------------
   Purpose:
   Styles the descriptive label below a KPI value with smaller, muted text.
   ========================================================================== */
.kpi-label {
  margin-top: 0.25rem;
  color: var(--bs-secondary-color);
  font-size: 0.85rem;
  font-weight: 500;
}

/* ==========================================================================
   Empty KPI state
   --------------------------------------------------------------------------
   Purpose:
   Displays a muted empty-state message when no KPI data is available.
   ========================================================================== */
.kpi-empty {
  color: var(--bs-secondary-color);
  font-size: 1.25rem;
}

.drawer-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  background: #fff;
}

.drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 20px;
  background: linear-gradient(135deg, var(--cv-surface-subtle) 0%, #fff 100%);
  border-bottom: 1px solid var(--cv-border-panel);
  flex-shrink: 0;
  min-width: 0;
}

.drawer-header-icon {
  font-size: 1.4rem;
  color: var(--cv-primary-brand);
}

.drawer-header-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--cv-text-heading);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.drawer-header-title i {
  font-size: 0.65rem;
  color: var(--cv-text-muted);
  vertical-align: middle;
  margin: 0 2px;
}

.drawer-close-btn {
  flex-shrink: 0;
  margin-left: auto;
  align-self: center;
}

.drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}
.drawer-body .table td:first-child {
  width: 40%;
}

.drawer-shadow .dxbl-drawer-panel {
  box-shadow: -6px 0 20px rgba(0, 0, 0, 0.12), -2px 0 6px rgba(0, 0, 0, 0.06);
  border-left: 1px solid var(--cv-border-panel);
}

.drawer-history {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--cv-border-section);
}

.drawer-history-list {
  max-height: 300px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.drawer-history-item {
  padding: 8px 0;
  border-bottom: 1px solid var(--cv-border-faint);
}
.drawer-history-item:last-child {
  border-bottom: none;
}

.drawer-history-date {
  font-size: 0.75rem;
  color: var(--cv-text-muted);
  margin-bottom: 2px;
}

.drawer-history-event {
  font-size: 0.85rem;
  color: var(--cv-text-dark);
  line-height: 1.4;
}

.drop-down-button-container {
  position: relative;
  height: 2.65em;
  min-width: 75px;
}
.drop-down-button-container .dxbl-btn {
  height: 100% !important;
  padding: unset !important;
}
.drop-down-button-container .dxbl-btn .status-wrapper .status-text {
  padding-right: 0.25rem;
}
.drop-down-button-container .drop-down-button-items {
  z-index: 9999;
  position: absolute;
  width: fit-content;
  min-width: 100%;
  background-color: white;
  /* Reset default styling for a unordered list */
  list-style-type: none;
  padding: 0;
  margin: 2px 0 0;
  border: 1px solid var(--cv-border-input);
  border-radius: 0.125rem;
}
.drop-down-button-container .drop-down-button-items.align-right {
  right: 0;
}
.drop-down-button-container .drop-down-button-items[data-is-visible] {
  display: none;
}
.drop-down-button-container .drop-down-button-items[data-is-visible=true] {
  display: block;
}
.drop-down-button-container .drop-down-button-items .drop-down-button-item {
  cursor: pointer;
  white-space: nowrap;
  padding: 0.5rem 1.25rem;
  background-color: #ffffff;
}
.drop-down-button-container .drop-down-button-items .drop-down-button-item:hover {
  background-color: var(--cv-secondary);
}

/* ==========================================================================
   Placeholder picker
   --------------------------------------------------------------------------
   Purpose:
   Styles the two halves of the insert-placeholder UI: the button that sits
   inside a PlaceholderTextBox editor, and the PlaceholderDropDown list it
   shares with the SimpleHtmlEditor toolbar button. The drop-down is rendered
   in a body-level portal, so it cannot be reached from either component's
   scoped stylesheet and lives here instead.
   ========================================================================== */
.placeholder-text-box {
  width: 100%;
  /* Keep the button's label on one line and compact; the editor shrinks the input to fit it. */
}
.placeholder-text-box .placeholder-text-box-button {
  white-space: nowrap;
  padding: 0 0.5rem;
  font-size: 0.9em;
  color: var(--cv-text-muted);
}
.placeholder-text-box .placeholder-text-box-button:hover {
  color: var(--cv-primary-brand);
}

/* The SimpleHtmlEditor's menu hangs off an empty marker covering the whole toolbar strip rather than off the
   DevExpress toolbar button itself: the button is DevExpress' markup, so whether its CssClass reaches the rendered
   element is not ours to rely on, and a PositionTarget that matches nothing leaves the menu unplaced. The marker
   spans the strip, so the menu drops out of the toolbar's left edge and stays inside the popup it lives in. */
.simple-html-editor {
  position: relative;
}
.simple-html-editor .simple-html-editor-placeholder-anchor {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* The Fluent toolbar strip's height; the menu drops from just below it. */
  height: 2.5rem;
  pointer-events: none;
}

.placeholder-drop-down {
  /* Sized by its longest group name rather than by a guessed pixel width, which either cut the labels off or
     left a gap in front of the chevrons. !important because DevExpress writes the popup width inline. */
  width: max-content !important;
  min-width: 11rem;
  max-width: 22rem;
  /* The scroll sits on this wrapper rather than on the menu: a height limit on the menu itself makes DevExpress
     render its own scroll arrows on top of the scrollbar and clip the first item. The search box stays outside
     it, so it holds still while the list moves under it. */
}
.placeholder-drop-down .placeholder-drop-down-body {
  display: flex;
  flex-direction: column;
  padding: 0.25rem;
}
.placeholder-drop-down .placeholder-drop-down-search {
  margin-bottom: 0.25rem;
}
.placeholder-drop-down .placeholder-drop-down-scroll {
  max-height: 16rem;
  overflow-y: auto;
}
.placeholder-drop-down .placeholder-drop-down-menu {
  border: none;
  background: transparent;
}

/* Compact rows at the body font size, matching the toolbar dropdown this menu replaced. SizeMode.Small was tried
   for this and shrank the type along with the rows, so the tightening happens on the padding alone. The submenu
   popup renders body-level, so it carries the same rules through its own class rather than through the
   drop-down's. */
.placeholder-drop-down,
.placeholder-drop-down-submenu {
  /* DevExpress renders every menu item as an anchor and the app paints links brand-orange. A placeholder is not
     a link, so the item takes the body text colour and weight back. */
}
.placeholder-drop-down .dxbl-menu-item,
.placeholder-drop-down-submenu .dxbl-menu-item {
  min-height: 0 !important;
  padding: 0.15rem 0.5rem !important;
}
.placeholder-drop-down .dxbl-menu-item-list,
.placeholder-drop-down-submenu .dxbl-menu-item-list {
  padding: 0.15rem 0 !important;
}
.placeholder-drop-down .dxbl-menu-item,
.placeholder-drop-down .dxbl-menu-item a,
.placeholder-drop-down .dxbl-menu-item-text,
.placeholder-drop-down-submenu .dxbl-menu-item,
.placeholder-drop-down-submenu .dxbl-menu-item a,
.placeholder-drop-down-submenu .dxbl-menu-item-text {
  color: var(--cv-text-primary);
  font-weight: 400;
  text-decoration: none;
}

.placeholder-drop-down-submenu {
  width: max-content !important;
  max-width: 22rem;
  max-height: 16rem;
  overflow-y: auto;
}

.events-container {
  margin-top: 15px;
  overflow-y: auto;
  height: 450px;
  padding: 0 0 15px 15px;
}
.events-container h1 {
  font-size: 1em;
  font-weight: bold;
}
.events-container .navigation-event, .events-container .historic-event {
  margin-bottom: 12px;
}
.events-container .navigation-event label, .events-container .historic-event label {
  font-size: 0.875em;
  font-weight: 600;
  display: block;
}
.events-container .navigation-event span, .events-container .historic-event span {
  font-size: 0.875em;
}
.events-container .navigation-event .dxbl-btn {
  padding: 0;
  text-align: left;
}
.events-container .navigation-event .dxbl-btn span {
  font-size: 0.875rem;
  color: black;
}
.events-container .navigation-event .dxbl-btn > .dxbl-image {
  background: var(--cv-surface-icon-bg);
  border-radius: 20px;
  padding: 10px;
  height: 2.5em;
  width: 3em;
}

/* ==========================================================================
   Keyboard shortcut keys
   --------------------------------------------------------------------------
   Purpose:
   Renders shortcut chords as physical keycaps instead of Bootstrap's dark
   inline <kbd>. Used by the header hint that opens the shortcut help overlay
   (the bi-keyboard glyph was unreadable at menu icon size) and by the chord
   column inside that overlay.
   ========================================================================== */
.keycap-group {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  white-space: nowrap;
}

.keycap {
  display: inline-block;
  min-width: 1.8em;
  padding: 0.15em 0.5em;
  font-family: inherit;
  font-size: 0.9em;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  color: var(--cv-text-dark);
  background: linear-gradient(#ffffff, var(--cv-surface-icon-bg));
  border: 1px solid var(--cv-border-muted);
  border-radius: 0.375rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 2px 0 rgba(0, 0, 0, 0.12);
}

/* Header hint: scaled down and flattened so the caps sit level with the 16px menu icons. */
.keycap-sm {
  min-width: 1.4em;
  padding: 0.05em 0.35em;
  font-size: 0.75em;
  line-height: 1.3;
  color: var(--cv-text-muted);
  border-color: var(--cv-border);
  border-radius: 0.25rem;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
}

/* Fixed width so the chord column in the help overlay stays aligned. */
.shortcut-help-key {
  min-width: 7.5rem;
}

/* ==========================================================================
   Gantt planning board
   --------------------------------------------------------------------------
   Purpose:
   Styles for the Gantt planning tab. Covers the page layout and toolbar
   (rendered by Blazor) plus the DevExtreme Gantt widget DOM (task bars,
   progress fill, tooltip, strip lines, non-working-day
   shading) which is created by JavaScript and therefore cannot be reached by
   component-scoped styles. Also covers the legend and the minimap strip.
   ========================================================================== */
.gantt-overview {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: 0.5rem;
}

/* Single cohesive toolbar bar: filters on the left, view controls on the right. Rendered as one padded surface card so
   the two control clusters read as a single bar even when they wrap on a narrow viewport. */
.gantt-toolbar {
  display: flex;
  justify-content: space-between;
  /* Bottom-align the two clusters so every control (filter inputs, period nav, zoom levels, gear/info) sits on one
     shared baseline and every label lines up across the top, even though the clusters differ slightly in height. */
  align-items: flex-end;
  gap: 0.6rem 1.25rem;
  flex-wrap: wrap;
  padding: 0.5rem 0.75rem;
  background: #fff;
  border: 1px solid var(--cv-border-panel);
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}

.gantt-toolbar-filters,
.gantt-toolbar-actions {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.gantt-toolbar-actions {
  gap: 0.6rem;
}

.gantt-filter {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.gantt-filter-label {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cv-text-secondary);
}

.gantt-filter-info {
  color: var(--cv-text-muted);
  cursor: help;
  font-size: 0.85rem;
  text-transform: none;
}

.gantt-filter-input {
  min-width: 165px;
}

.gantt-option-icon {
  margin-right: 7px;
  vertical-align: middle;
  color: var(--cv-text-secondary);
}

/* Cap the height of the filter drop-downs' option list. The status filter lists every status across nine entity groups
   (~30 options), which made the drop-down grow to fill the whole viewport. Constraining the popup body (the
   MultiSelectListBoxDropDown's marker element, which only the Gantt filters use) to a flex column with a max height
   keeps the popup compact: the inner DxListBox is `height: 100%` (see _form.scss) so it fills the capped box and its
   own scroll viewer scrolls the options, while the search and "select all" header stay pinned above. The list box
   renders in a DevExpress popup outside the component DOM, so this lives in the global sheet rather than a scoped one. */
.multiselect-listbox {
  display: flex;
  flex-direction: column;
  max-height: min(58vh, 380px);
}

/* The gear (view options) icon carries no label, so the toolbar's flex-end alignment would pin its short glyph box to the
   very bottom - below the optical centre of the taller controls next to it. Matching its box height to the standard 32px
   control row (see the 2.25em zoom segment and the 32px button min-height) and centring the glyph lands it on the same
   line as the Year / Zoom controls. A fixed px height (not em) keeps it aligned. */
.gantt-options-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  /* Nudge the bare icon a few px lower so it sits slightly toward the bottom of the control row, matching the gear
     placement the design calls for. */
  position: relative;
  top: 3px;
}

/* The view-options menu (gear drop-down) reuses the grid toolbar's own `grid-buttongroup-button` item class so its size
   matches the grid options menu - see GridToolbar.razor. The menu items deliberately do NOT carry the `active` class
   (the `.grid-buttongroup-button.active` bold + brand-colour rule in layout/_grid.scss): state is carried by the item
   icon alone - a toggle (`bi-toggle-on` / `bi-toggle-off`) for on/off options and a check for the picked option in a
   choice list. No gantt-specific menu styling is needed. */
/* The "What do these options do?" help entry is the menu's lead item: rendered in the Conventus brand orange accent
   (icon, a soft tint and a left accent bar) with bold black text, so it stands out as the way in to the options guide
   while matching the app's standard orange highlight instead of an off-brand colour. */
.gantt-options-guide-item {
  color: var(--cv-text-primary);
  font-weight: 700;
  background: color-mix(in srgb, var(--cv-primary) 12%, transparent);
  box-shadow: inset 3px 0 0 var(--cv-primary);
}
.gantt-options-guide-item .dxbl-btn-icon,
.gantt-options-guide-item i {
  color: var(--cv-primary);
}
.gantt-options-guide-item:hover {
  background: color-mix(in srgb, var(--cv-primary) 18%, transparent);
}

/* Options guide modal (opened from the top item of the view-options menu): a muted intro line about interacting with the
   timeline, a type-to-filter search box, then one titled section per option group (Display, Order and grouping, Moving
   items) laid out in balanced columns so the wide modal shows most options without scrolling. Each option is an icon-led
   row whose icon mirrors that option's entry in the menu, with its bold term over a muted description so the block scans
   as an icon legend rather than a wall of even-weight text. The popup body renders in a body-level DevExpress overlay, so
   it is styled from the global sheet, not a scoped one. */
.gantt-options-guide {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
}

.gantt-options-guide-intro {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--cv-text-secondary);
}

/* Type-to-filter box over the guide's options: a bordered field with a leading search glyph that lifts to the info
   accent on focus. The trailing clear control is the browser's native one (from the search input). */
.gantt-options-guide-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--cv-border-input);
  border-radius: 8px;
  background: #fff;
}
.gantt-options-guide-search:focus-within {
  border-color: var(--cv-status-info);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--cv-status-info) 18%, transparent);
}

.gantt-options-guide-search-icon {
  flex: 0 0 auto;
  color: var(--cv-text-secondary);
  font-size: 0.9rem;
}

.gantt-options-guide-search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-size: 0.85rem;
  color: var(--cv-text-primary);
}
.gantt-options-guide-search-input::placeholder {
  color: var(--cv-text-secondary);
}

/* The sections tile into balanced columns (masonry-like); each section is kept whole, never split across a break. Falls
   back to a single column on a narrow viewport. */
.gantt-options-guide-sections {
  column-count: 2;
  column-gap: 1.1rem;
}

.gantt-options-guide-empty {
  margin: 0;
  padding: 1.25rem;
  text-align: center;
  font-style: italic;
  font-size: 0.85rem;
  color: var(--cv-text-secondary);
}

.gantt-options-guide-section {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--cv-border-section);
  border-radius: 8px;
  overflow: hidden;
  break-inside: avoid;
  margin-bottom: 1.1rem;
}

@media (max-width: 720px) {
  .gantt-options-guide-sections {
    column-count: 1;
  }
}
/* Section header: the section icon and its title on a subtle bar, matching the reschedule list's header treatment. */
.gantt-options-guide-section-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  background: var(--cv-surface-subtle);
  border-bottom: 1px solid var(--cv-border-section);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cv-text-secondary);
}

.gantt-options-guide-section-icon {
  color: var(--cv-primary);
  font-size: 0.9rem;
}

.gantt-options-guide-rows {
  display: flex;
  flex-direction: column;
  background: #fff;
}

/* One option: its menu icon in a fixed gutter, then the bold term over a muted description. A hairline divider sets each
   row off from the next so the options read as a list. */
.gantt-options-guide-row {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.65rem 0.75rem;
}
.gantt-options-guide-row + .gantt-options-guide-row {
  border-top: 1px solid var(--cv-border-section);
}

.gantt-options-guide-row-icon {
  flex: 0 0 auto;
  width: 1.25rem;
  margin-top: 0.1rem;
  text-align: center;
  color: var(--cv-primary);
  font-size: 0.95rem;
}

.gantt-options-guide-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.gantt-options-guide-term {
  color: var(--cv-text-primary);
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1.3;
}

.gantt-options-guide-desc {
  color: var(--cv-text-secondary);
  font-size: 0.8rem;
  line-height: 1.4;
}

.gantt-empty {
  padding: 1rem;
  color: var(--cv-text-secondary);
  font-style: italic;
}

.gantt-container {
  flex: 1 1 auto;
  min-height: 480px;
  /* Own stacking context pinned below the footer (z-index 1) so the chart's internal separators and strip lines can
     never paint over the legend popover that floats up from the footer. */
  position: relative;
  z-index: 0;
}

/* The board footer: the legend on the left and the board controls on the right, on one shared baseline so the controls
   sit opposite the legend labels rather than floating over the chart. */
.gantt-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  /* Sits above the chart's stacking context (z-index 0) so the legend popover floats cleanly over the board. */
  position: relative;
  z-index: 1;
}

/* Board controls anchored to the footer's right edge: a zoom slider plus DevExpress switches for the task list and
   activities. They drive the same state as the toolbar zoom selector and the view-options menu, so the three stay in
   lock-step. */
.gantt-floating-controls {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.gantt-floating-zoom {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  cursor: help;
}

.gantt-floating-zoom-icon {
  font-size: 0.9rem;
  color: var(--cv-text-secondary);
  cursor: pointer;
}
.gantt-floating-zoom-icon:hover {
  color: var(--cv-primary);
}

/* Native range input styled into a compact track + thumb so it reads as a slim zoom slider on the floating bar. */
.gantt-floating-slider {
  -webkit-appearance: none;
  appearance: none;
  width: 96px;
  height: 4px;
  border-radius: 2px;
  /* Brand-tinted track + thumb so the zoom slider reads in the app's colour rather than the browser default blue. */
  background: color-mix(in srgb, var(--cv-primary) 35%, #fff);
  outline: none;
  cursor: pointer;
  accent-color: var(--cv-primary);
}
.gantt-floating-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--cv-primary);
  border: 2px solid #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.gantt-floating-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--cv-primary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.gantt-floating-zoom-label {
  min-width: 48px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--cv-text-primary);
}

/* Lay the two switches out in a row (task list, activities) to the right of the slider. */
.gantt-floating-switches {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

/* Keep each switch's caption compact and on one line so the floating bar stays slim. */
.gantt-floating-switch {
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}

/* ==========================================================================
   Minimap
   ========================================================================== */
/* A full-width, compressed overview of the whole timeline below the chart (opt-in, off by default, toggled like the
   other view options). Every scheduled bar shows as a tick coloured by its entity colour; the brand-tinted box marks -
   and drags to pan - the slice the chart currently shows. Drawn client-side in Overview.razor.js. */
.gantt-minimap {
  border-top: 1px solid rgba(0, 0, 0, 0.08);
  padding: 0.4rem 0 0.1rem;
}
.gantt-minimap.is-hidden {
  display: none;
}

/* The strip stretches horizontally to the container (preserveAspectRatio="none"), so its x-axis IS the time scale. */
.gantt-minimap-svg {
  display: block;
  width: 100%;
  height: 54px;
  background: rgba(0, 0, 0, 0.02);
  border-radius: 4px;
  cursor: pointer;
}

/* Task ticks: clicks fall through to the SVG track rather than landing on a bar. */
.gantt-minimap-tick {
  pointer-events: none;
}

/* Marker bands: outline only (transparent fill + a coloured border) so the strip mirrors the chart's strip lines now that
   those dropped their solid wash. One class per category, coloured to match its chart band (today red, holidays indigo,
   weekends teal). Non-scaling stroke keeps the border an even 1px despite the strip's horizontal stretch; clicks fall
   through to the track. */
.gantt-minimap-today,
.gantt-minimap-holiday,
.gantt-minimap-weekend {
  fill: none;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}

.gantt-minimap-today {
  stroke: rgba(229, 0, 0, 0.65);
}

.gantt-minimap-holiday {
  stroke: rgba(99, 102, 241, 0.6);
}

.gantt-minimap-weekend {
  stroke: rgba(13, 148, 136, 0.5);
}

/* The viewport box: the slice the chart shows, brand-tinted and draggable. Non-scaling stroke keeps the outline even
   despite the horizontal stretch. */
.gantt-minimap-viewport {
  fill: var(--cv-primary);
  fill-opacity: 0.14;
  stroke: var(--cv-primary);
  stroke-width: 1.5;
  vector-effect: non-scaling-stroke;
  cursor: grab;
}
.gantt-minimap-viewport:active {
  cursor: grabbing;
}

/* ==========================================================================
   Legend
   ========================================================================== */
/* The footer legend is a slim pill ("Legend" + a colour-dot peek). Its full body opens as a popover ABOVE the pill, so
   expanding or collapsing it never changes the footer's height — the chart is never resized and the page never grows or
   jumps. The pill stays in flow; only the popover is taken out of it. */
.gantt-legend {
  flex: 0 0 auto;
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.2rem 0.1rem;
  font-size: 0.74rem;
  color: var(--cv-text-secondary);
}

/* Borderless pill that opens/closes the legend popover. Tints toward the brand colour on hover so it reads as actionable. */
.gantt-legend-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
  padding: 0.15rem 0.55rem 0.15rem 0.4rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--cv-text-secondary);
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.gantt-legend-toggle:hover {
  background: color-mix(in srgb, var(--cv-primary) 10%, transparent);
  color: var(--cv-primary);
}
.gantt-legend-toggle:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--cv-primary) 55%, transparent);
  outline-offset: 1px;
}

/* Chevron points up (toward where the popover appears) while closed; flips to point down once open. */
.gantt-legend-chevron {
  font-size: 0.7rem;
  line-height: 1;
  transition: transform 0.26s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.gantt-legend:not(.is-collapsed) .gantt-legend-chevron {
  transform: rotate(180deg);
}

/* Always-on colour-dot peek inside the pill: a slim at-a-glance key of the entity-type palette while the full popover is
   closed. Sits after the label behind a hairline divider; decorative — the labelled swatches live in the popover. */
.gantt-legend-peek {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
  margin-left: 0.1rem;
  padding-left: 0.55rem;
  border-left: 1px solid var(--cv-border-panel);
}
.gantt-legend-peek .gantt-legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.18);
}

/* The popover card. Anchored to the pill and floated just above it (bottom: 100%), it is absolutely positioned so it sits
   OVER the chart's lower edge rather than pushing anything — opening it cannot grow the page. Mirrors the toolbar card's
   surface (#fff + panel border + 10px radius). */
.gantt-legend-body {
  position: absolute;
  left: 0;
  bottom: calc(100% + 8px);
  z-index: 40;
  /* Size to the content, not to the slim pill that is its positioning context — otherwise the card shrink-wraps to the
     pill's width and the rows clamp into cramped columns. max-content lays "Markers" and "Types" each out on one line;
     the viewport guard keeps a very wide card from running off the right edge (it would wrap rather than overflow). */
  width: max-content;
  max-width: calc(100vw - 2rem);
  background: #fff;
  border: 1px solid var(--cv-border-panel);
  border-radius: 10px;
  /* A hairline ring plus a deep, soft drop shadow so the card lifts clearly off the chart behind it. */
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 18px 44px rgba(0, 0, 0, 0.22), 0 6px 16px rgba(0, 0, 0, 0.12);
  padding: 0.95rem 1.25rem;
  opacity: 1;
  transform: translateY(0) scale(1);
  transform-origin: bottom left;
  transition: opacity 0.18s ease, transform 0.22s cubic-bezier(0.34, 1.45, 0.64, 1);
}

/* Closed: faded, nudged down, and click-through so it neither shows nor intercepts pointer events. */
.gantt-legend.is-collapsed .gantt-legend-body {
  opacity: 0;
  transform: translateY(10px) scale(0.97);
  pointer-events: none;
}

.gantt-legend-rows {
  /* Lay both rows on one shared grid so the Markers and Types items line up in columns. display:contents on each row
     (below) flattens its label + items into this grid, and the title forces a fresh row via grid-column:1. The 10 item
     columns cover the Types row (the longest — one per entity type); the Markers row leaves its trailing columns empty. */
  display: grid;
  grid-template-columns: auto repeat(10, max-content);
  column-gap: 1.4rem;
  row-gap: 0.6rem;
  align-items: center;
  /* Pack each item against the left edge of its column (instead of stretching to fill it) so the swatch + label of the
     Markers and Types rows line up flush down each column. */
  justify-items: start;
}

@media (prefers-reduced-motion: reduce) {
  .gantt-legend-chevron,
  .gantt-legend-body {
    transition: none;
  }
}
/* A legend row is no longer its own flex line: display:contents flattens its label + items into the shared
   .gantt-legend-rows grid so both rows' items align in columns. */
.gantt-legend-row {
  display: contents;
}

.gantt-legend-title {
  /* Pinned to the grid's first column, which forces each row to start fresh (and keeps "Markers"/"Types" in their own
     aligned column); the right-hand sideline separates the label column from its items. */
  grid-column: 1;
  min-width: 5.5rem;
  padding-right: 0.65rem;
  border-right: 1px solid var(--cv-border-panel);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 0.68rem;
}

.gantt-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* The Tooltip wraps each Markers swatch/glyph in an anchor span (id^="tooltip-anchor") that carries a scoped
   `margin: 0 8px`; Types items have no Tooltip, so only the Markers row inherits it and ends up shifted 8px right of the
   Types row. Zero that margin inside the legend — the descendant selector plus the id attribute (specificity 0,3,0) beats
   the scoped two-attribute rule (0,2,0) — so both rows' swatches sit flush at their shared column's left edge. The
   inter-item spacing still comes from .gantt-legend-item's own gap. */
.gantt-legend-item .gantt-legend-target[id^=tooltip-anchor] {
  margin: 0;
}

.gantt-legend-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
  /* Today marker: the same hatch + border the today strip line now renders (transparent fill, no solid wash). */
  /* Holiday band: the exact 45 degree hatch + border the holiday strip line renders (transparent fill, no solid wash). */
  /* Weekend band: the exact 45 degree hatch + border the weekend strip line renders (transparent fill, no solid wash). */
}
.gantt-legend-swatch.is-high {
  background: var(--cv-primary);
  box-shadow: inset 4px 0 0 0 var(--cv-status-red);
}
.gantt-legend-swatch.is-locked {
  background-image: repeating-linear-gradient(45deg, rgba(0, 0, 0, 0.35) 0, rgba(0, 0, 0, 0.35) 4px, rgba(0, 0, 0, 0.1) 4px, rgba(0, 0, 0, 0.1) 8px);
  background-color: var(--cv-text-secondary);
}
.gantt-legend-swatch.is-today {
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(229, 0, 0, 0.22) 0, rgba(229, 0, 0, 0.22) 2px, transparent 2px, transparent 7px);
  box-shadow: inset 0 0 0 1px rgba(229, 0, 0, 0.45);
}
.gantt-legend-swatch.is-holiday {
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(99, 102, 241, 0.22) 0, rgba(99, 102, 241, 0.22) 2px, transparent 2px, transparent 7px);
  box-shadow: inset 0 0 0 1px rgba(99, 102, 241, 0.45);
}
.gantt-legend-swatch.is-weekend {
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(13, 148, 136, 0.22) 0, rgba(13, 148, 136, 0.22) 2px, transparent 2px, transparent 7px);
  box-shadow: inset 0 0 0 1px rgba(13, 148, 136, 0.45);
}

/* ==========================================================================
   Task bar (rendered by the taskContentTemplate)
   ========================================================================== */
.gantt-bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  /* Fill the task element DevExtreme has already positioned/sized to the task's date span. Without this the bar
     collapses to label width and looks like no bar at all. */
  width: 100%;
  /* Shorter than the row so bars read denser, in line with the rest of the app. Centred via `top` (the bar is the
     only child of the DevExtreme task element, so this works without depending on the container being flex). */
  height: 62%;
  top: 19%;
  border-radius: 5px;
  padding: 0 8px;
  overflow: hidden;
  background-color: var(--cv-primary);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.18), rgba(0, 0, 0, 0.08));
  color: #fff;
  box-sizing: border-box;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  transition: box-shadow 0.12s ease;
  /* Derived work order activity: a thinner, hatched bar signalling it has no hard planned date. */
  /* Synthetic swimlane group summary row. */
}
.gantt-bar:hover {
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.28);
}
.gantt-bar.gantt-bar-high {
  box-shadow: inset 4px 0 0 0 var(--cv-status-red), 0 1px 2px rgba(0, 0, 0, 0.18);
}
.gantt-bar.gantt-bar-readonly {
  opacity: 0.7;
}
.gantt-bar.gantt-bar-unscheduled {
  background-color: var(--cv-text-secondary);
  background-image: none;
  border: 1px dashed rgba(255, 255, 255, 0.85);
}
.gantt-bar.gantt-bar-activity {
  height: 58%;
  align-self: center;
  border-radius: 3px;
  background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.28) 0, rgba(255, 255, 255, 0.28) 4px, transparent 4px, transparent 8px);
}
.gantt-bar.gantt-bar-group {
  background-color: #5b6b7b;
  background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(0, 0, 0, 0.12));
  border-radius: 4px;
  opacity: 0.92;
}
.gantt-bar.gantt-bar-group .gantt-bar-label {
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* Status-derived completion fill, painted as a darker overlay over the bar's own colour. */
.gantt-bar-progress {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.22);
  border-right: 1px solid rgba(255, 255, 255, 0.4);
  pointer-events: none;
}

.gantt-bar-label {
  position: relative;
  flex: 1 1 auto;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
}

.gantt-bar-avatars {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
}

.gantt-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: -6px;
  border-radius: 50%;
  border: 1.5px solid #fff;
  background-color: rgba(0, 0, 0, 0.35);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1;
  box-sizing: border-box;
}
.gantt-avatar:first-child {
  margin-left: 0;
}
.gantt-avatar.gantt-avatar-more {
  background-color: rgba(0, 0, 0, 0.55);
}

/* ==========================================================================
   Task bar fill (the default DevExtreme bar element, .dx-gantt-task)
   --------------------------------------------------------------------------
   The board renders default DevExtreme bars (a custom taskContentTemplate would
   drop the dependency connectors) and deliberately omits tasks.colorExpr, so
   DevExtreme does NOT paint the entity colour as the bar's inline background and
   flood the whole row with it. Instead each bar wrapper carries the entity
   colour as --entity-color (set by syncWrapperColor in Overview.razor.js); the
   rules below paint a faint entity-tinted body with the colour as a solid LEFT
   EDGE and a dark entity-coloured label. This keeps every row's entity
   recognisable without the saturated full-bar fill, so a dense board reads calm.
   The colour falls back to the brand colour for any row without an entity colour
   (e.g. a synthetic group row).
   ========================================================================== */
.dx-gantt {
  /* Status-completion fill: a stronger wash of the entity colour over the tinted body (the former dark overlay would read
     as a second colour now the body is light), capped with a crisp entity-tinted divider at the completion boundary. Sits
     below the title (titleIn is z-index 1). */
  /* Dark, entity-coloured label - readable on the light body, replacing the white-on-colour text the full-fill bar used. */
  /* Reserve a fixed left slot on the inside-the-bar label so its text always starts at the same offset whether or not the
     "no dates" warning glyph is shown - the glyph is drawn into this slot (see .gantt-bar-flag / syncWrapperWarning), so a
     scheduled and an unscheduled bar keep their labels aligned. Kept in sync with BarLabelInsetPx in Overview.razor.js,
     which sets the same padding inline so it holds when the built app.css is stale. (The small-task / outside-text variants
     set their own padding, so this only affects the normal inside label.) */
  /* Milestones are tiny rotated diamonds where a left edge makes no sense - keep them a solid entity fill. */
}
.dx-gantt .dx-gantt-task {
  /* Faint tint of the entity colour, not a solid fill. */
  background-color: color-mix(in srgb, var(--entity-color, var(--cv-primary)) 12%, #fff);
  /* Hairline in a slightly stronger tint so a pale bar never vanishes on the white chart, with the entity colour as a
     solid 4px left edge. A real left border (not an inset shadow) so the progress fill, which starts inside the border
     box, never paints over the accent. */
  border: 1px solid color-mix(in srgb, var(--entity-color, var(--cv-primary)) 35%, #fff);
  border-left: 4px solid var(--entity-color, var(--cv-primary));
  border-radius: 5px;
  box-sizing: border-box;
}
.dx-gantt .dx-gantt-tPrg {
  background-color: color-mix(in srgb, var(--entity-color, var(--cv-primary)) 26%, #fff);
  border-right: 1px solid color-mix(in srgb, var(--entity-color, var(--cv-primary)) 45%, #fff);
}
.dx-gantt .dx-gantt-taskTitle {
  color: color-mix(in srgb, var(--entity-color, var(--cv-primary)) 78%, #000);
  font-weight: 600;
}
.dx-gantt .dx-gantt-titleIn {
  padding-left: 20px;
}
.dx-gantt .dx-gantt-task.dx-gantt-milestone {
  background-color: var(--entity-color, var(--cv-primary));
  border: none;
}

/* Amber "no dates" warning drawn just INSIDE the left of an unscheduled item's bar - a wrapper child positioned by
   syncWrapperWarning in Overview.razor.js (into the label's reserved left slot, see .dx-gantt-titleIn), mirroring the same
   warning on the left of the task-list row. Sits inside the bar's left edge and centred on it; non-interactive so it never
   sits over the bar's thin left resize grip and swallows the press. */
.gantt-bar-flag {
  position: absolute;
  transform: translate(0, -50%);
  font-size: 0.82rem;
  line-height: 1;
  color: var(--cv-status-warning);
  pointer-events: none;
  z-index: 3;
}

/* ==========================================================================
   Timeline decorations and tooltip
   ========================================================================== */
/* Today marker: a centred band in a distinct cool red - same width as the indigo holiday bands but a different colour - so
   the two never read as the same thing. Its width comes from its date span (set in buildStripLines); the only sizing here is
   a `min-width` floor so the band stays visible when zoomed out (where the centred half-day span shrinks to a
   near-invisible hairline), while the span still drives the width whenever it is wider.

   Gotcha: strip-line bands must stay pointer-INERT (the engine's strip-line layer disables pointer events; never
   re-enable them here). The bands overlay the whole chart column full-height, ABOVE the task bars - a hit-testable band
   swallows the mousedown of any bar under it (above all a task planned IN the weekend, fully under the weekend band),
   so the engine never starts the drag and the held button then hover-retargets other rows ("dragging jumps to another
   task"). The marker names are surfaced on the day-scale HEADER cells instead (see onScaleCellPrepared). */
.dx-gantt .dx-gantt-ti.gantt-today-stripline {
  /* Same 45deg hatch + side borders as the holiday band, in red instead of amber, so today reads as a soft band
     (not a hard solid bar) while staying distinct from the indigo holidays. Transparent fill, no solid wash. */
  min-width: 6px;
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(229, 0, 0, 0.22) 0, rgba(229, 0, 0, 0.22) 2px, transparent 2px, transparent 7px);
  border-left: 1px solid rgba(229, 0, 0, 0.45);
  border-right: 1px solid rgba(229, 0, 0, 0.45);
}

/* Holiday band: a hatched indigo band spanning a holiday's whole date range, drawn as a strip line so it stays
   visible at every zoom level (the day-header cell tint only renders at the days scale). The indigo hatch sets a holiday
   apart from the teal weekend band and reads as a block even when the band is only a day or two wide. A `min-width` floor
   keeps the band visible once the date span shrinks to a hairline at coarse zoom. The holiday's name is shown by hovering
   its day-scale HEADER cell (see onScaleCellPrepared) - the band itself must stay pointer-inert (see the today-marker
   note above). */
.dx-gantt .dx-gantt-ti.gantt-holiday-stripline {
  /* Transparent fill (no solid wash) so the indigo hatch + side borders carry the band. */
  min-width: 6px;
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(99, 102, 241, 0.22) 0, rgba(99, 102, 241, 0.22) 2px, transparent 2px, transparent 7px);
  border-left: 1px solid rgba(99, 102, 241, 0.45);
  border-right: 1px solid rgba(99, 102, 241, 0.45);
}

/* Weekend band: the exact same 45deg hatch + side borders as the today / holiday bands (same intensities, no solid
   wash), in a soft teal so all three marker categories share one visual language while never reading as the same thing (today red,
   holidays indigo, weekends teal). Each weekend day is drawn as its own centred band (see buildWeekendStripLines) at the
   same width as the today / holiday markers. Toggleable per category in the view options; pointer-inert like the other
   bands (see the today-marker note above) so a bar planned in the weekend stays draggable. */
.dx-gantt .dx-gantt-ti.gantt-weekend-stripline {
  min-width: 6px;
  background-color: transparent;
  background-image: repeating-linear-gradient(45deg, rgba(13, 148, 136, 0.22) 0, rgba(13, 148, 136, 0.22) 2px, transparent 2px, transparent 7px);
  border-left: 1px solid rgba(13, 148, 136, 0.45);
  border-right: 1px solid rgba(13, 148, 136, 0.45);
}

/* Marker header cells: tint a day-header cell that is a weekend / holiday - and the active-scale cell over today - to
   match its strip-line band (weekends teal, holidays indigo, today red), so a header column reads the same as the band
   below it. Each cell class is stamped in onScaleCellPrepared; each rule is scoped to its own .gantt-markers-* root gate
   (see applyMarkerHeaderGates) so it clears live with that marker toggle. A bottom inset accent echoes the band's side
   borders without shifting the cell box. Ordered weekend -> holiday -> today (equal specificity) so that on a day that is
   several at once the most specific meaning wins on the shared properties: holiday over weekend, today over both. */
.dx-gantt.gantt-markers-weekends .dx-gantt-si.gantt-weekend-header {
  background-color: rgba(13, 148, 136, 0.1);
  box-shadow: inset 0 -2px 0 0 rgba(13, 148, 136, 0.55);
  color: rgb(13, 148, 136);
}

.dx-gantt.gantt-markers-holidays .dx-gantt-si.gantt-holiday-header {
  background-color: rgba(99, 102, 241, 0.1);
  box-shadow: inset 0 -2px 0 0 rgba(99, 102, 241, 0.55);
  color: rgb(79, 82, 210);
}

.dx-gantt.gantt-markers-today .dx-gantt-si.gantt-today-header {
  background-color: rgba(229, 0, 0, 0.1);
  box-shadow: inset 0 -2px 0 0 rgba(229, 0, 0, 0.55);
  color: rgb(178, 0, 0);
  font-weight: 600;
}

/* ISO week-number badge (e.g. "wk 29") prepended to each week-scale header cell - the day view's top tier and the week
   view's own cells - by stampWeekNumber in Overview.razor.js. A compact accent-coloured prefix set off from the cell's
   date range by a hairline divider, so the week number reads at a glance without crowding the header. */
.gantt-week-number {
  margin-right: 0.5em;
  padding-right: 0.5em;
  border-right: 1px solid var(--cv-border-section);
  color: var(--cv-primary);
  font-weight: 600;
}

/* Drag / resize editing skeleton + grab handles.
   DevExtreme draws only a 1px frame border (#269aff) on the edit wrapper and 5px-wide resize handles at the bar edges.
   That made resize feel arbitrary in two ways: (1) the 5px edge handle is easy to miss, so a resize often does not start
   at all ("not responding"); (2) once it starts the thin same-colour frame overlaps the still-full-width original bar,
   so the skeleton is invisible - worst when shrinking, where the frame sits entirely inside the bar.
   Fixes: widen the grab handles for a reliable target, and give the active edit state a translucent accent fill plus a
   bold haloed border. DevExtreme adds `.move` to the wrapper for drag AND both resize handles, so this one rule covers
   move and resize; the white halo separates the orange edge from the bar so the new size reads even over a solid bar.
   Accent orange (--cv-primary) contrasts with the blue task bars (and matches the today strip line). */
.dx-gantt {
  /* Narrow-bar grip relocation (gantt-edit-narrow, toggled by syncNarrowEditGrips in Overview.razor.js). The engine
     starts a MOVE from a press on the centre frame and a RESIZE from a press on a start/end grip, and the grips above
     are fixed 10px overlays INSIDE the frame. The engine renders bars down to 2px wide, so at coarse zoom levels (week
     and beyond) a short bar sits entirely under its own grips: every press started a resize, a move - and with it the
     sub-tree cascade and a sane auto-extend - was unreachable anywhere coarser than day zoom. When the interop flags
     the wrapper as narrow (width < 24px), both grips move fully OUTSIDE the frame: the whole bar becomes the move zone
     again and the 10px just past either edge still resizes (the engine classifies by element, not position, so the
     relocated grips keep their roles). Wide bars - every bar at day zoom - keep the stock inside grips, preserving the
     settled day-zoom feel including the single-day-parent resize-first tradeoff (see docs/gotchas.md). */
  /* Disable the completion-% drag node. The task-edit overlay renders a small wedge handle (.dx-gantt-task-edit-progress,
     a sibling of the start/end resize handles and the move frame) at the top of a bar's progress fill that a user can drag
     to change the task's percent-complete. The board plans dates only - the completion fill (.dx-gantt-tPrg) is derived
     server-side from the entity's status, never set by the planner - so removing this handle prevents an edit the board
     does not persist (onTaskUpdating cancels a progress-only change) while leaving move (frame) and resize (start/end)
     handles untouched. dxGantt exposes no editing.allowTaskProgressUpdating flag, so the handle is disabled here rather
     than via a widget option. display:none also lets the press fall through to the move frame beneath. !important so it
     wins unconditionally over the engine's own structural rule (dx-gantt.min.css) regardless of stylesheet load order. */
  /* Live drag-preview ghosts (drawn by the interop on a bar drag), each a CHILD of its row's bar wrapper so it rides the
     chart's scroll / pan / zoom for free. Two roles share this base skeleton: a translucent ghost over every movable
     descendant, slid by the drag delta via transform so the whole sub-tree previews the atomic reschedule the drop performs
     (gantt-ghost), and a static marker over the dragged bar's original position (gantt-ghost-origin). Non-interactive and
     dashed to read as a preview, not a real bar. */
  /* The dragged item's origin marker: a muted, neutral dashed outline left over the bar's original position. Unlike the
     orange sub-item ghosts it does not slide - it marks where the move started ("from here") while the orange sliding ghosts
     show where the sub-tree lands ("to there"), so the two never read as the same thing. Shown for every drag, including a
     leaf item (e.g. a work order) that has no movable sub-items and therefore no sliding ghosts. */
  /* An auto-extended ancestor's stretch ghost: overlays the ancestor bar and reaches to the child's new end, previewing the
     parent growing to cover the overflowing child. Recoloured BLUE (vs the orange sub-item ghosts) and badged with an
     "extending" label so the parent's own preview reads as a distinct auto-extend, not part of the child's move; drawn with
     a SOLID right edge marking the new end the drop saves. */
  /* The stretch ghost's "extending" badge: a small pill pinned to the ghost's new-end (right) edge carrying the localized
     label the interop writes to data-label. Blue to match the recoloured extend ghost, so it reads as one auto-extend cue.
     Non-interactive; ellipsised so a narrow ghost never spills the label past its row. */
  /* Non-working accent on the edit frame: when the dragged window's start or end lands on a weekend/holiday the interop
     adds this class for the frame, recolouring the orange move accent amber-red so the warning reads while dragging. An
     advisory cue only - the drop still commits (the server applies no calendar rule). */
}
.dx-gantt .dx-gantt-task-edit-start,
.dx-gantt .dx-gantt-task-edit-end {
  width: 10px;
}
.dx-gantt .dx-gantt-task-edit-wrapper.gantt-edit-narrow .dx-gantt-task-edit-start {
  left: -10px;
}
.dx-gantt .dx-gantt-task-edit-wrapper.gantt-edit-narrow .dx-gantt-task-edit-end {
  right: -10px;
}
.dx-gantt .dx-gantt-task-edit-progress {
  display: none !important;
}
.dx-gantt .dx-gantt-task-edit-wrapper.move {
  background-color: rgba(240, 126, 38, 0.18);
  border-radius: 5px;
}
.dx-gantt .dx-gantt-task-edit-wrapper.move .dx-gantt-task-edit-frame {
  border: 2px solid var(--cv-primary);
  border-radius: 5px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.55);
}
.dx-gantt .gantt-ghost {
  position: absolute;
  z-index: 11;
  box-sizing: border-box;
  border: 2px dashed var(--cv-primary);
  border-radius: 5px;
  background-color: rgba(240, 126, 38, 0.18);
  pointer-events: none;
}
.dx-gantt .gantt-ghost-origin {
  border-color: rgba(122, 134, 148, 0.9);
  background-color: rgba(122, 134, 148, 0.12);
}
.dx-gantt .gantt-ghost-extend {
  border-style: dashed solid dashed dashed;
  border-color: var(--cv-status-info);
  background-color: color-mix(in srgb, var(--cv-status-info) 20%, transparent);
}
.dx-gantt .gantt-ghost-extend::after {
  content: attr(data-label);
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  max-width: calc(100% - 8px);
  padding: 0 6px;
  border-radius: 8px;
  background-color: var(--cv-status-info);
  color: #fff;
  font-size: 10px;
  font-weight: 600;
  line-height: 15px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
.dx-gantt .dx-gantt-task-edit-wrapper.move.gantt-edit-nonworking {
  background-color: rgba(255, 167, 0, 0.22);
}
.dx-gantt .dx-gantt-task-edit-wrapper.move.gantt-edit-nonworking .dx-gantt-task-edit-frame {
  border-color: var(--cv-status-warning);
}

/* Keep the edit skeleton visible for the WHOLE gesture, not only while the engine's transient `.move` class is on the
   wrapper. DevExtreme appends `.move` per drag frame (processStart / processEnd / processMove) but RESETS the wrapper's
   className to the base class on any mid-gesture re-show / re-layout (confirmStart / confirmEnd and the internal re-shows),
   which blanks the `.move`-only styling above so the skeleton vanishes for that gesture even though the resize still
   commits - the intermittent "no skeleton on resize". body.gantt-bar-editing is OUR flag, set on the primary-button press
   and cleared just after release (onBarPointerDown / onBarPointerUp), so it spans the whole gesture regardless of the
   engine stripping `.move`. Mirror the orange fill + haloed frame off that flag so the skeleton is stable. Scoped to an
   active press (never mere hover, which sets no flag), so it adds no hover noise. */
body.gantt-bar-editing .dx-gantt .dx-gantt-task-edit-wrapper {
  background-color: rgba(240, 126, 38, 0.18);
  border-radius: 5px;
}
body.gantt-bar-editing .dx-gantt .dx-gantt-task-edit-wrapper .dx-gantt-task-edit-frame {
  border: 2px solid var(--cv-primary);
  border-radius: 5px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.55);
}

/* Hide the widget's own drag date tooltip while our readout is up, so a gesture shows a single tooltip, not two. The
   interop flags <body> with gantt-dragging for the readout's lifetime - a move raises it from onTaskMoving, a resize from
   the polled edit-frame loop (see updateDragReadout / updateResizeReadout). The substring match covers the tooltip and
   its before/after/default segments. */
body.gantt-dragging [class*=dx-gantt-task-edit-tooltip] {
  display: none !important;
}

/* While a bar is being dragged or resized, suppress the hover peek flyout so it cannot float over the bar mid-gesture (a
   slow grab of the thin resize handle outlasts the flyout's reveal delay) and so its over-allocation "open details" button
   cannot be clicked by accident as the drag is released - which would open the info modal on top of the resize. Scoped to
   the flyout overlay only: the widget's own drag date tooltip is governed separately by the gantt-dragging flag above, so
   date feedback survives until the custom readout takes over. The interop flags <body> with gantt-bar-editing on a
   primary-button press over a bar and clears it just after release (see onBarPointerDown / onBarPointerUp in
   Overview.razor.js). */
body.gantt-bar-editing .dx-overlay-content.gantt-flyout-overlay {
  display: none !important;
}

/* Belt-and-braces: the strip bands are pointer-inert at ALL times now (see the marker styles above) - a hit-testable
   band over a bar swallowed the bar's own mousedown, so a task planned in the weekend could not be dragged at all and
   the engine's gesture state derailed for the whole hold. This gesture-scoped rule stays as a backstop so no future
   band variant can regress mid-drag behaviour. */
body.gantt-bar-editing .gantt-today-stripline,
body.gantt-bar-editing .gantt-holiday-stripline,
body.gantt-bar-editing .gantt-weekend-stripline {
  pointer-events: none;
}

/* A held drag must not start a text selection (task-list titles, header cells): a selection visibly smears across the
   board and its native drag behaviour competes with the engine's gesture. */
body.gantt-bar-editing .gantt-overview {
  user-select: none;
}

/* Live drag readout: a small pill beside the dragged bar - on the dragged row itself, leading the gesture's moving
   edge - showing the new start–end window and day span (drawn by the interop in updateDragReadout). Kept off the
   adjacent rows so it never covers the parent's auto-extend ghost above or a sub-item's slide preview below.
   Positioned in the task area's coordinate space, so it tracks the bar and scrolls with the chart; non-interactive so
   it never intercepts the drag. The is-nonworking modifier and its note appear when an end lands on a weekend/holiday. */
.gantt-drag-readout {
  position: absolute;
  z-index: 12;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 4px 11px;
  border-radius: 8px;
  /* Solid (no alpha) so it reads sharply over any bar colour. */
  background-color: #1f2933;
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
}
.gantt-drag-readout.is-nonworking {
  background-color: var(--cv-status-warning);
  border-color: #b87400;
  color: #1f1300;
}

.gantt-drag-readout-note {
  display: inline-flex;
  align-items: center;
  font-weight: 700;
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.gantt-drag-readout-note::before {
  content: "⚠";
  margin-right: 0.25rem;
}

/* The Tooltip wrapper around a legend glyph/swatch: keeps the glyph inline with its label and shows a help cursor so it
   reads as hoverable. */
.gantt-legend-target {
  display: inline-flex;
  align-items: center;
  cursor: help;
}

/* Field label above the title-format input in the title-format popup. */
.gantt-title-format-label {
  display: block;
  margin: 0.6rem 0 0.25rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--cv-text-secondary);
}

/* ==========================================================================
   Reschedule review modal
   --------------------------------------------------------------------------
   The "before you save" dialog shown on a drag/resize: one row per touched
   item (the dragged item plus every sub-item that moves with it) with its
   current window struck through and the proposed window in the brand colour,
   so the planner sees exactly what changes. Styled to match the app's cards
   and the create-orders popup (subtle surfaces, hairline dividers, brand
   accents). The DxPopup body renders in a body-level overlay, so this lives
   in the global sheet rather than a scoped one.
   ========================================================================== */
.gantt-reschedule-review {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.gantt-reschedule-intro {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--cv-text-secondary);
}

.gantt-reschedule-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--cv-border-section);
  border-radius: 8px;
  overflow: hidden;
  transition: opacity 0.15s ease;
  /* A weekend-toggle re-fetch is in flight: dim the rows (and park the pointer) until the new proposals swap in, so
     the flip visibly takes effect even before the re-fetched dates arrive. */
}
.gantt-reschedule-list.is-reloading {
  opacity: 0.55;
  pointer-events: none;
}

/* Column header for the change list: muted uppercase labels (matching the toolbar filter labels) over the item and the
   from → to columns, pinned above the scrolling rows. */
.gantt-reschedule-head {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.45rem 0.75rem;
  background: var(--cv-surface-subtle);
  border-bottom: 1px solid var(--cv-border-section);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cv-text-secondary);
}

.gantt-reschedule-head-item {
  flex: 1 1 auto;
}

.gantt-reschedule-head-dates {
  /* Same fixed width as each row's dates block below, so the label sits centred over the from -> to columns. */
  flex: 0 0 28rem;
  max-width: 100%;
  text-align: center;
}

/* Scroll the rows (not the whole popup) once the list grows tall, so the column header, intro and footer stay in view. */
.gantt-reschedule-rows {
  max-height: 42vh;
  overflow-y: auto;
}

/* One touched item: type icon, the item's number + name, and its from → to windows. The hairline divider sets each row
   off from the next; the dragged item (.is-parent) gets a tinted surface and a brand left-accent so it leads the list. */
.gantt-reschedule-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.75rem;
  background: #fff;
}
.gantt-reschedule-row + .gantt-reschedule-row {
  border-top: 1px solid var(--cv-border-section);
}
.gantt-reschedule-row.is-parent {
  background: var(--cv-surface-subtle);
  border-left: 3px solid var(--cv-primary);
  /* The accent border sits inside the row's box (border-box), so it would push this row's content 3px right of
     the other rows'; eating it out of the padding keeps the leading checkboxes in one straight column. */
  padding-left: calc(0.75rem - 3px);
}

.gantt-reschedule-icon {
  flex: 0 0 auto;
  font-size: 1.05rem;
  color: var(--cv-primary);
}

.gantt-reschedule-item {
  display: flex;
  flex-direction: column;
  /* The item absorbs the row's free space and ellipsizes its number/name; the dates block keeps a fixed width so its
     from -> to columns line up across every row (see .gantt-reschedule-dates). */
  min-width: 7rem;
  flex: 1 1 auto;
}

.gantt-reschedule-number {
  font-weight: 700;
  color: var(--cv-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gantt-reschedule-name {
  font-size: 0.8rem;
  color: var(--cv-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The dates column reads as a table: a fixed-width three-track grid (old | arrow | new) that never shrinks, so the same
   columns line up on every row. The old window is muted and struck through and right-aligned toward the arrow; the arrow
   sits in the centre; the new window is bold in the brand colour and left-aligned from the arrow - so the change reads at
   a glance and the arrows and new dates stack into clean columns down the list. Each window carries a now/becomes label
   (see .gantt-reschedule-datelabel) so which date is which survives the deselected emphasis flip. Each window stays on
   one line (nowrap). The whole block collapses to a simple right-aligned wrap on a very narrow popup (see the media
   query below). */
.gantt-reschedule-dates {
  flex: 0 0 28rem;
  max-width: 100%;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  column-gap: 0.4rem;
  font-size: 0.8rem;
}

.gantt-reschedule-old {
  text-align: right;
  color: var(--cv-text-secondary);
  text-decoration: line-through;
  white-space: nowrap;
}

/* The now/becomes prefix inside the old/new spans. Inline-block on purpose: a parent's text-decoration does not
   propagate into an inline-block, so the label never gets struck through with its date. */
.gantt-reschedule-datelabel {
  display: inline-block;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cv-text-secondary);
}

.gantt-reschedule-arrow {
  text-align: center;
  color: var(--cv-text-secondary);
  font-size: 0.75rem;
}

.gantt-reschedule-new {
  text-align: left;
  font-weight: 700;
  color: var(--cv-primary);
  white-space: nowrap;
}

/* An unticked row is excluded from the reschedule: its content dims and the date emphasis flips to tell the true story
   - the current window reads plain (it stays), the proposed window is muted and struck through (it will not happen) -
   so a row that does not move is unmistakable at a glance. The leading checkbox keeps full strength so re-including
   stays inviting. Applies to the gantt change rows and the linked-appointment rows alike. */
.gantt-reschedule-row.is-deselected .gantt-reschedule-icon,
.gantt-reschedule-row.is-deselected .gantt-reschedule-item,
.gantt-reschedule-row.is-deselected .gantt-reschedule-dates {
  opacity: 0.5;
}
.gantt-reschedule-row.is-deselected .gantt-reschedule-old {
  text-decoration: none;
}
.gantt-reschedule-row.is-deselected .gantt-reschedule-new {
  font-weight: 400;
  color: var(--cv-text-secondary);
  text-decoration: line-through;
}

/* Very narrow popup (small screens, where 95vw is far below the desktop width): drop the fixed table and let the windows
   wrap right-aligned again, since the three fixed columns no longer fit beside the item. */
@media (max-width: 640px) {
  .gantt-reschedule-head-dates {
    flex: 0 0 auto;
    text-align: right;
  }
  .gantt-reschedule-dates {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.15rem 0.4rem;
  }
}
/* Linked calendar appointments folded into the review popup: the labelled section head below sets the section off from
   the gantt changes above, then its own heading and intro, and the same row layout with a leading checkbox so each
   appointment can be ticked. */
.gantt-reschedule-linked {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin-top: 0.35rem;
}

/* Section head as a labelled divider: icon chip + title with a hairline filling the rest of the line, so each of the
   popup's two sections (project planning / linked appointments) starts with an unmistakable boundary. */
.gantt-reschedule-section-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.gantt-reschedule-section-head::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--cv-border-section);
}

/* The section icon sits in a small brand-tinted chip so the head reads as a header rather than a body line. */
.gantt-reschedule-section-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.65rem;
  height: 1.65rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--cv-primary) 12%, #fff);
  color: var(--cv-primary);
  font-size: 0.95rem;
}

.gantt-reschedule-section-title {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--cv-text-primary);
  white-space: nowrap;
}

/* Nudge the row's leading checkbox down to the top of the row content so it lines up with the appointment subject. */
.gantt-reschedule-check {
  flex: 0 0 auto;
  align-self: center;
}

.gantt-reschedule-conflict {
  margin-top: 0.15rem;
  font-size: 0.75rem;
  color: var(--cv-danger, #dc3545);
}

/* The uniform day-offset line under the linked-appointments intro ("Verschuiving: +7 dag(en)."). */
.gantt-reschedule-shift {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--cv-text-primary);
}

/* Weekend callout at the top of the review popup: the shared NoticeBanner control carries the banner styling; only
   the popup-specific spacing below it lives here. Hidden entirely when nothing touches the weekend. */
.gantt-reschedule-weekends {
  margin: 0 0 0.65rem;
}

/* Neutral per-row note (e.g. lifted over the weekend): informative, not alarming. */
.gantt-reschedule-rowinfo {
  margin-top: 0.15rem;
  font-size: 0.75rem;
  color: var(--cv-text-secondary);
}

/* ==========================================================================
   Custom title format popup
   --------------------------------------------------------------------------
   The planner edits a template (e.g. "[Number] - [Name] ([Status])") applied
   to every bar label and task-list title. The input's "insert placeholder"
   button adds an item property at the caret, mirroring the e-mail template editor.
   ========================================================================== */
.gantt-title-format {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.gantt-title-format-intro {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--cv-text-secondary);
}

/* A little breathing room below the template input before the next label / the popup footer. */
.gantt-title-format-field {
  margin-bottom: 0.85rem;
}

/* ==========================================================================
   Date editors in the info modal (shown for an editable item)
   --------------------------------------------------------------------------
   Below the read-only entity card, set the item's start/end (or a single
   milestone date) with pickers, an alternative to dragging the bar's edges.
   Sits under a hairline separator so it reads as a distinct "edit" section.
   ========================================================================== */
.gantt-edit {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--cv-border-section);
}

/* Section heading ("Edit dates") introducing the pickers. */
.gantt-edit-heading {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 700;
  color: var(--cv-text-primary);
}

.gantt-edit-heading-icon {
  color: var(--cv-primary);
}

.gantt-edit-title {
  font-size: 0.9rem;
}

.gantt-edit-intro {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--cv-text-secondary);
}

/* The pickers: start and end side by side (a single-date item shows just one), each wrapping to full width when narrow.
   Gap matches the action buttons' gap (Bootstrap gap-2 = 0.5rem) so each picker's inner edge lines up with the button below it. */
.gantt-edit-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.gantt-edit-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  flex: 1 1 10rem;
  min-width: 0;
}

.gantt-edit-label {
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--cv-text-secondary);
}

.gantt-edit-input {
  width: 100%;
}

/* Inline hint when the range ends before it starts (the one rule the server also enforces); the Save button is disabled
   while it shows, so this only explains why. */
/* The modal's action buttons ("Open detail" / "Save"): a zero flex-basis so the two split exactly 50/50 regardless of
   their differing label lengths, keeping each button's inner edge aligned with the date picker above it. A single button
   still grows to fill the full width. */
.gantt-edit-action {
  flex: 1 1 0;
}

/* ==========================================================================
   Hover flyout (rendered by renderTaskFlyout through the widget's tooltip hook)
   --------------------------------------------------------------------------
   A light "peek" card: entity number, name, status and planning window. The
   click-opened info modal shows the full entity card (relation,
   key numbers, tags, last-updated line) via the GanttInfoCard Blazor component.
   ========================================================================== */
/* Positioner for the hover flyout shared by the strip lines (today / holiday) and the bar-warning glyphs: a body-level box
   that follows the cursor (set in wireHoverFlyout). It carries no chrome of its own - the inner .gantt-flyout card does -
   and ignores pointer events so it never blocks the hover that drives it. Sits above the chart and the dx tooltip overlay. */
.gantt-stripline-flyout {
  position: fixed;
  z-index: 2200;
  pointer-events: none;
}

/* The strip-line / bar-glyph note reuses the .gantt-flyout card but renders only a single caption line, so the 320px
   min-width meant for the rich task peek made the one-liner read far too wide. Shrink this variant to its content (capped
   so a long holiday name still wraps rather than running off-screen). */
.gantt-stripline-flyout .gantt-flyout {
  width: max-content;
  min-width: 0;
  max-width: 320px;
}

.gantt-flyout {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.6rem 0.7rem;
  min-width: 320px;
  max-width: 440px;
  text-align: left;
  color: var(--cv-text-primary);
  /* The tooltip overlay lives outside .dx-gantt and inherits the DevExtreme fluent font plus its `line-height: 0`, so the
     flyout text rendered in the wrong typeface and cramped. Pin it to the app font and a normal line-height. */
  font-family: var(--conventus-font-family);
  font-size: 0.8rem;
  line-height: 1.4;
  /* The card chrome lives on this element (the content wrapper we render), not the dx tooltip overlay frame: the gantt
     task tooltip's .dx-overlay-content box is sized/positioned independently of the rendered content, so a background on
     it did not sit under the flyout (it read as transparent over the bars). Painting the wrapper makes a solid popover
     card regardless of how the overlay frame is laid out. */
  background: #fff;
  border: 1px solid var(--cv-border-section);
  /* Cap the card with the entity's own bar colour so the flyout reads as belonging to the bar it describes, and gives
     the otherwise plain white card a spot of colour. Falls back to the brand colour when no entity colour is set. */
  border-top: 3px solid var(--entity-color, var(--cv-primary));
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
  /* Entity-type glyph in a rounded chip tinted to the entity's bar colour, mirroring the stock forecast flyout's icon. */
  /* Status as a colour pill: a tinted background and darkened text both derived from the status-palette colour, so even
     a light status (e.g. Draft) reads in its own colour rather than as a near-white, invisible dot. The plain
     declarations are fallbacks for browsers without color-mix. */
}
.gantt-flyout .gantt-flyout-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Set the number/status header off from the detail rows with the same hairline divider the stock forecast flyout uses. */
  padding-bottom: 0.45rem;
  border-bottom: 1px solid var(--cv-border-section);
}
.gantt-flyout .gantt-flyout-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  font-size: 0.85rem;
  background: rgba(0, 0, 0, 0.06);
  background: color-mix(in srgb, var(--entity-color, var(--cv-primary)) 16%, #fff);
  color: var(--entity-color, var(--cv-primary));
}
.gantt-flyout .gantt-flyout-number {
  font-weight: 700;
  font-size: 0.92rem;
  color: var(--cv-text-primary);
}
.gantt-flyout .gantt-flyout-status {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: auto;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--cv-text-secondary);
  color: color-mix(in srgb, var(--status-color, var(--cv-text-secondary)) 72%, #000);
  background: var(--cv-border-section);
  background: color-mix(in srgb, var(--status-color, var(--cv-text-secondary)) 16%, #fff);
}
.gantt-flyout .gantt-flyout-status-dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18);
}
.gantt-flyout .gantt-flyout-title {
  font-weight: 700;
}
.gantt-flyout .gantt-flyout-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  font-size: 0.8rem;
  line-height: 1.45;
}
.gantt-flyout .gantt-flyout-key {
  flex: 0 0 auto;
  color: var(--cv-text-secondary);
  font-weight: 600;
}
.gantt-flyout .gantt-flyout-value {
  text-align: right;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Popover-card chrome for the hover flyout. The dx-gantt structural stylesheet leaves the task tooltip's overlay frame
   unthemed (no surface, border or shadow), so the flyout read as almost invisible. Theme the frame (tagged with
   gantt-flyout-overlay by renderTaskFlyout) as a proper card matching the app's other flyouts - white surface, hairline
   border, soft shadow, rounded corners - while the inner .gantt-flyout keeps the layout and padding. The overlay lives on
   <body>, outside .dx-gantt. */
.dx-overlay-content.gantt-flyout-overlay {
  /* The card chrome is on .gantt-flyout (the content wrapper); neutralize the dx tooltip frame so it neither paints a
     competing square box behind the rounded card nor clips its shadow. !important overrides the dx fluent theme's
     .dx-tooltip-wrapper .dx-overlay-content rule (equal specificity, loaded after app.css). */
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  overflow: visible !important;
  /* Click-through. The flyout is a body-level overlay floating above the task bars, so once it has revealed (past the
     two-second hover delay - the "slow grab of the thin resize handle" case) a default pointer-events:auto frame swallows
     the mousedown aimed at the bar's thin resize grip beneath it: the grip never gets the press (the bar will not resize),
     and the gesture flag that hides this flyout for an edit (onBarPointerDown in Overview.razor.js, bound to the chart
     element - NOT this body-level overlay) never arms, so the flyout also stays stuck over the bar. Making the frame
     transparent to the pointer lets the press pass straight through to the grip, which both starts the resize and arms that
     flag (which then hides the flyout for the gesture). The one actionable element - the "open details" button - re-enables
     pointer events below so it stays clickable. */
  pointer-events: none !important;
}

/* The dx tooltip nests our content under .dx-popup-content; drop its theme padding so the card's own padding is the only
   inset and the rounded corners are not boxed by an inner pad. */
.dx-overlay-content.gantt-flyout-overlay .dx-popup-content {
  padding: 0 !important;
}

/* The tooltip's OUTER overlay wrapper must be as click-through as its content: the dx theme can hit-test the wrapper
   itself, which re-swallows the press aimed at the thin resize grip under the flyout even with the content transparent -
   the bar then cannot be resized while the flyout is up. */
.dx-overlay-wrapper:has(> .dx-overlay-content.gantt-flyout-overlay) {
  pointer-events: none !important;
}

/* Hover-reveal delay gate: the widget shows the task tooltip immediately on hover and exposes no delay option, so the
   interop (deferTooltip) hides the tooltip's overlay frame for two seconds and reveals it only if the pointer is still on
   the bar. !important overrides DevExtreme's inline fade-in opacity; the overlay lives on <body>, outside .dx-gantt. */
.dx-overlay-content.gantt-tooltip-pending {
  opacity: 0 !important;
  pointer-events: none;
}

.dx-gantt .dx-gantt-toolbar .dx-button-mode-contained.dx-state-hover {
  background-color: rgba(240, 126, 38, 0.12);
}

/* ==========================================================================
   Task list cells (rendered by the column cellTemplates) and compact rows
   --------------------------------------------------------------------------
   The Title cell is prefixed with the entity-type icon and the Status cell
   leads with a status-coloured dot (reusing the bar colour), mirroring how the
   app's other overviews show status.
   ========================================================================== */
.gantt-cell-title {
  display: inline-flex;
  align-items: center;
  /* Space between the entity-type icon and the title text (the cell has only those two children). */
  gap: 0.6rem;
  min-width: 0;
  /* Nudge the entity-type icon (and title) a little right of the tree expand control so it is not cramped. */
  margin-left: 0.25rem;
}

.gantt-cell-icon {
  flex: 0 0 auto;
  font-size: 0.95rem;
  line-height: 1;
  color: var(--cv-text-secondary);
}

.gantt-cell-title-text {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* The Title cell text is the only click target that opens the info modal; style it like the navigatable cells in the
   app's grid overviews (.grid-cell-link): primary colour, pointer cursor, underline on hover. */
.gantt-cell-title-link {
  color: var(--bs-primary);
  cursor: pointer;
}
.gantt-cell-title-link:hover {
  text-decoration: underline;
  color: var(--bs-primary);
}

/* Amber "no dates" warning leading an unscheduled row's title (see renderTitleCell): it sits before the entity-type icon on
   the row's LEFT edge, spaced from the icon by the .gantt-cell-title flex gap. */
.gantt-cell-flag {
  flex: 0 0 auto;
  font-size: 0.9rem;
  line-height: 1;
}

.gantt-cell-flag-missing {
  color: var(--cv-status-warning);
}

.gantt-cell-status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.gantt-cell-status-dot {
  flex: 0 0 auto;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
}

/* Compact rows. dxGantt exposes no rowHeight option; the chart syncs its row height to the task list, so trimming the
   task-list cell padding and font size shortens both panes together. Fails safe: if these treelist selectors do not
   match a given DevExtreme build, the rows simply keep their default height (nothing breaks). */
.dx-gantt .dx-treelist .dx-row > td {
  padding-top: 4px;
  padding-bottom: 4px;
}
.dx-gantt .dx-treelist .dx-data-row {
  font-size: 0.8rem;
}

/* ==========================================================================
   Info modal (opened on double-click) — the entity summary styled like the
   swimlane board drawer (reuses the shared .drawer-panel classes, see
   _drawer-panel.scss) but kept as a centred popup under the standard popup
   header, with the event log as a second column beside the details.
   ========================================================================== */
/* The popup keeps its own DevExpress header bar, like every other popup in the application; only the body padding is
   dropped so the two columns sit flush to the popup edge. !important overrides the DevExpress theme defaults; scoped to
   this popup via its CssClass so no other popup is affected. */
.gantt-info-popup .dxbl-modal-content {
  overflow: hidden;
}

.gantt-info-popup .dxbl-popup-content,
.gantt-info-popup .dxbl-modal-content,
.gantt-info-popup .dxbl-modal-body {
  padding: 0 !important;
}

.gantt-info-modal {
  display: flex;
  flex-direction: column;
  height: auto;
  max-height: 78vh;
  background: #fff;
}

/* Details on the left, event log on the right; each column scrolls on its own so the header stays put. */
.gantt-info-modal-body {
  display: flex;
  align-items: stretch;
  min-height: 0;
  overflow: hidden;
}

.gantt-info-modal-details {
  flex: 0 0 460px;
  max-width: 460px;
  padding: 16px 20px;
  overflow-y: auto;
  scrollbar-width: thin;
}

.gantt-info-modal-events {
  flex: 1 1 auto;
  min-width: 260px;
  padding: 16px 20px;
  overflow-y: auto;
  border-left: 1px solid var(--cv-border-section);
  background: var(--cv-surface-subtle);
  scrollbar-width: thin;
  /* Event/relations toggle header and the relations list mirror the swimlane drawer; those classes are scoped to the
     swimlane component, so the equivalent rules are replicated here for the Gantt modal. */
}
.gantt-info-modal-events .drawer-history-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.5rem;
}
.gantt-info-modal-events .drawer-history-header .view-mode-toggle i {
  font-size: 1rem;
  transition: color 0.2s ease;
}
.gantt-info-modal-events .drawer-links-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.gantt-info-modal-events .drawer-link-item {
  padding: 0.5rem 0.625rem;
  border-radius: 0.375rem;
  border: 1px solid var(--cv-border-section);
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.gantt-info-modal-events .drawer-link-item:hover {
  background-color: #fff;
}
.gantt-info-modal-events .drawer-link-item .drawer-link-title {
  font-size: 0.875rem;
  font-weight: 600;
}
.gantt-info-modal-events .drawer-link-item .drawer-link-meta {
  font-size: 0.75rem;
  color: var(--cv-text-secondary);
  margin-top: 0.125rem;
}

html, body, #app {
  height: 100%;
  width: 100%;
}

/* Prevent text selection during drag */
.no-select,
.no-select * {
  user-select: none !important;
  -webkit-user-select: none !important;
  -ms-user-select: none !important;
  -moz-user-select: none !important;
}

@media (max-width: 576px) {
  html, body {
    font-size: 11px;
    --bs-body-font-size: 11px;
  }
}
@media (min-width: 576px) {
  html, body {
    font-size: 12px;
    --bs-body-font-size: 12px;
  }
}
@media (min-width: 768px) {
  html, body {
    font-size: 13px;
    --bs-body-font-size: 13px;
  }
}
/*# sourceMappingURL=app.css.map */
