/* ==========================================================================
   Q88Web Components — Phase 2 (Building Blocks)

   Consumes tokens from tokens.css. Adds modern styling patterns.
   Loading order: tokens.css → MainWhiteout.css → [Q88|Milbros]Whiteout.css → components.css

   SCOPED: All selectors in sections 0-12 prefixed with .q88-refresh to limit
   visual refresh to dashboard page only. The sidebar has its own font/color
   declarations in navigation.css (applied on all sidebar-enabled pages).

   Sections:
   0. Typography (shadcn font mapping)
   1. Base Utilities (transitions, focus rings)
   2. Buttons
   3. Module Templates (Cards)
   4. Alerts / Notifications
   5. Loading Overlay
   6. Modals
   7. Content Tabs
   8. Popup Menus
   9. Calendar
   10. Grid Overrides (DevExpress)
   11. FleetVessel
   12. ComboBox
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Typography (shadcn font mapping)

   Shifts Q88 from Arial ~12px to Inter 14px base. Four-step scale:
   xs (12px), sm (14px), base (16px), lg (18px).
   Weights: normal (400), medium (500), semibold (600).

   !important used ONLY on:
   - Inline style overrides (a.mainnav, #divCookie)
   - DevExtreme selectors (DX injects inline styles)
   -------------------------------------------------------------------------- */

/* --- Shared: Body reset --- */
.q88-refresh.BodyStyle {
  font-family: var(--font-family);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-normal);
  line-height: var(--line-height-sm);
}

/* --- Shared: Search --- */
.q88-refresh #ctl00_topWO_txtQuickSearch {
  font-size: var(--font-size-sm);
}

.q88-refresh .WaterMarkText {
  font-size: var(--font-size-sm);
  font-style: normal;
}

/* --- Shared: Footer --- */
.q88-refresh footer table td {
  font-size: var(--font-size-xs);
}

.q88-refresh footer a.whiteText {
  font-size: var(--font-size-xs);
}

/* --- Shared: Modals --- */
.q88-refresh .modPopTitlePnl span {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
}

.q88-refresh .consentText {
  font-size: var(--font-size-sm);
}

.q88-refresh .LinkButton.Secondary {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
}

/* --- Shared: Misc --- */
.q88-refresh .Disclaimer {
  font-size: var(--font-size-xs);
  color: var(--muted-foreground);
}

.q88-refresh #divCookie b {
  font-size: var(--font-size-lg) !important;
  font-weight: var(--font-weight-semibold) !important;
}

.q88-refresh #divCookie span {
  font-size: var(--font-size-sm) !important;
}

/* --- Shared: Old horizontal nav (visible when sidebar disabled) --- */
.q88-refresh #navMenuWO li.TopLevel > a {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  text-transform: none;
  letter-spacing: normal;
}

.q88-refresh #navMenuWO li.SubLevel > a {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-normal);
}

/* --- Classic Home --- */
.q88-refresh a.mainnav {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-medium);
}

/* --- Dashboard: DevExtreme typography --- */
.q88-refresh .dropdown-label {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-medium);
}

.q88-refresh .dx-texteditor-input {
  font-size: var(--font-size-sm) !important;
}

.q88-refresh .dx-list-item-content {
  font-size: var(--font-size-sm) !important;
}

.q88-refresh .dx-form-group-caption {
  font-size: var(--font-size-xs) !important;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.q88-refresh .dx-field-item-label-text {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-medium);
}

.q88-refresh .dx-field-item-content {
  font-size: var(--font-size-sm) !important;
}

.q88-refresh .dx-datagrid-headers td {
  font-size: var(--font-size-xs) !important;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.q88-refresh .dx-datagrid-rowsview td {
  font-size: var(--font-size-sm) !important;
}

.q88-refresh .dx-datagrid-filter-row input {
  font-size: var(--font-size-xs) !important;
}

.q88-refresh .dx-datagrid-pager {
  font-size: var(--font-size-xs) !important;
}

.q88-refresh .table-header {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-semibold);
}

.q88-refresh .dashboard-classic-switch {
  font-size: var(--font-size-sm);
  color: var(--muted-foreground);
}

.q88-refresh .NormalSmall {
  font-size: var(--font-size-xs);
  color: var(--muted-foreground);
}

.q88-refresh .dx-toolbar .dx-button-text {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-medium);
}

.q88-refresh .dx-datagrid .dx-button-text {
  font-size: var(--font-size-sm) !important;
  font-weight: var(--font-weight-medium);
}

/* --------------------------------------------------------------------------
   1. Base Utilities
   -------------------------------------------------------------------------- */

/* Universal transition for interactive elements */
.q88-refresh .LinkButton,
.q88-refresh .Secondary,
.q88-refresh .LinkButtonClicked,
.q88-refresh .popupMenuV2 .popupMenuItem,
.q88-refresh .ContentTab,
.q88-refresh .ContentTabOn {
  transition: background-color 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* Focus ring utility — accessible keyboard focus indicator */
.q88-refresh .LinkButton:focus-visible,
.q88-refresh .Secondary:focus-visible,
.q88-refresh .ContentTabLink:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   2. Buttons
   -------------------------------------------------------------------------- */

/* Primary button modernization
   a.LinkButton bumps specificity to match a:link (0,0,1,1) in MainWhiteout.css */
.q88-refresh a.LinkButton,
.q88-refresh .LinkButton {
  border-radius: 6px;
  padding: 6px 16px;
  border: none;
  background-color: var(--button-primary-bg);
  color: var(--button-primary-text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-decoration: none;
}

.q88-refresh .LinkButton:hover {
  background-color: var(--button-primary-hover);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
  text-decoration: none;
}

.q88-refresh .LinkButton:active {
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
}

/* Secondary button — outline style */
.q88-refresh .Secondary {
  background-color: transparent;
  border: 1px solid var(--primary);
  color: var(--primary);
  border-radius: 6px;
  padding: 6px 16px;
  cursor: pointer;
  font-weight: 500;
}

.q88-refresh .Secondary:hover {
  background-color: var(--surface-accent-hover);
  border-color: var(--button-primary-hover);
  color: var(--button-primary-hover);
}

/* Disabled / clicked state */
.q88-refresh .LinkButtonClicked,
.q88-refresh a.LinkButtonClicked,
.q88-refresh .LinkButtonClicked a {
  background-color: var(--disabled-foreground);
  border-radius: 6px;
  padding: 6px 16px;
  cursor: default;
  opacity: 0.7;
}

/* Slim variant */
.q88-refresh .LinkButton_Slim {
  border-radius: 4px;
  padding: 3px 10px;
}

/* Nested ins elements (button inner text) */
.q88-refresh .LinkButton ins,
.q88-refresh .Secondary ins,
.q88-refresh .LinkButtonClicked ins {
  text-decoration: none;
}

/* --------------------------------------------------------------------------
   2.a Global button promotion — body.sidebar-nav scope (QEN-8704)

   Mirrors the .q88-refresh primary/secondary/clicked rules above into the
   broader body.sidebar-nav scope so EVERY refreshed page gets the teal
   pill chrome — not just Home + SubscriptionList. Default.master.cs:393-397
   only adds .q88-refresh on the Home tab; on every other refreshed page
   the navy MainWhiteout.css base (L671) was winning.

   Also catches <asp:Button> (renders as <input type="submit|button">) so
   the ~60 pages that use Button instead of LinkButton get the same chrome
   without per-file CssClass edits. :not() guards exclude widget-managed
   inputs (DevExpress dx-/dxb/dxe, QQ uploader qq-, jQuery UI ui-) which
   carry their own skinning.

   Token resolution: tokens.css:393 binds --button-primary-* under
   body.sidebar-nav, so var() resolves to teal without a hex fallback.

   Longhand intentional — `background:` / `border:` shorthand with var()
   + !important triggers a Chrome CSSOM parser bug that silently drops
   the next declaration. MEMORY: css-shorthand-var-important-parser-trap.

   QEN-8801 Target B: !important removed. MainWhiteout.css:671's legacy navy
   button base is now scoped `body:not(.sidebar-nav)` (legacy pages only), so on
   refresh pages this block wins the NORMAL cascade — (0,2,1) beats legacy
   `a:link` navy (0,1,1). Longhand background-color/border-color stays the house
   style (the var() shorthand parser trap is moot now that !important is gone).
   -------------------------------------------------------------------------- */

body.sidebar-nav a.LinkButton,
body.sidebar-nav .LinkButton,
body.sidebar-nav input[type="submit"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]),
body.sidebar-nav input[type="button"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]) {
  background-color: var(--button-primary-bg);
  background-image: none;
  color: var(--button-primary-text);
  border: 1px solid var(--button-primary-bg);
  border-radius: 6px;
  padding: 6px 16px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-align: center;
  text-decoration: none;
  transition: background-color 0.15s ease, box-shadow 0.15s ease,
              border-color 0.15s ease, color 0.15s ease;
}

body.sidebar-nav a.LinkButton:hover,
body.sidebar-nav .LinkButton:hover,
body.sidebar-nav input[type="submit"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]):hover,
body.sidebar-nav input[type="button"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]):hover {
  background-color: var(--button-primary-hover);
  border-color: var(--button-primary-hover);
  color: var(--button-primary-text);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
  text-decoration: none;
}

/* QEN-8831 — primary-button hover = 90% opacity fade (Veson indigo brand).
   ONE central rule for the whole app, Q88 AND Milbros alike (Milbros rebrand
   follow-up: it now shares the same indigo tokens, so --button-primary-hover
   == --button-primary-bg on both portals and the color-swap rule above is a
   no-op everywhere — this opacity layer is the only visible hover feedback). */
body.sidebar-nav a.LinkButton:hover,
body.sidebar-nav .LinkButton:hover,
body.sidebar-nav input[type="submit"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]):hover,
body.sidebar-nav input[type="button"]:not([class*="dx-"]):not([class*="dxb"]):not([class*="dxe"]):not([class*="qq-"]):not([class*="ui-"]):hover,
/* Grid-action filled primaries — parallel --q88-grid-primary token family, not
   .LinkButton. Their color-swap hover (→ --q88-grid-primary-hover) is a no-op on
   the pages that map that token to var(--button-primary-hover) (= indigo base),
   so they need the opacity layer here too or they'd have no hover feedback. */
body.sidebar-nav .btn-primary:hover,
body.sidebar-nav .btn-add-new:hover,
body.sidebar-nav .om-btn--primary:hover,
body.sidebar-nav a.Img-Std-Add:hover,
body.sidebar-nav a:has(> img.Img-Std-Add):hover {
  opacity: 0.9;
}

body.sidebar-nav a.LinkButton:active,
body.sidebar-nav .LinkButton:active,
body.sidebar-nav input[type="submit"]:active,
body.sidebar-nav input[type="button"]:active {
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
}

/* Secondary — outline variant
   QEN-8801 Target B: !important removed. Legacy MainWhiteout.css `.Secondary`
   (#AAA) is now scoped `body:not(.sidebar-nav)`, so this NORMAL block (0,2,1 /
   0,3,1) wins on refresh pages by specificity + load order. */
body.sidebar-nav a.LinkButton.Secondary,
body.sidebar-nav .LinkButton.Secondary,
body.sidebar-nav input[type="submit"].Secondary,
body.sidebar-nav input[type="button"].Secondary,
body.sidebar-nav .Secondary {
  background-color: transparent;
  background-image: none;
  color: var(--button-primary-bg);
  border: 1px solid var(--button-primary-bg);
  border-radius: 6px;
  padding: 6px 16px;
  cursor: pointer;
  font-weight: 500;
  text-align: center;
}

body.sidebar-nav a.LinkButton.Secondary:hover,
body.sidebar-nav .LinkButton.Secondary:hover,
body.sidebar-nav input[type="submit"].Secondary:hover,
body.sidebar-nav input[type="button"].Secondary:hover,
body.sidebar-nav .Secondary:hover {
  background-color: var(--surface-hover-brand, rgba(var(--primary-tint), 0.08));
  border-color: var(--button-primary-hover);
  color: var(--button-primary-hover);
}

/* Disabled / clicked state */
body.sidebar-nav .LinkButtonClicked,
body.sidebar-nav a.LinkButtonClicked,
body.sidebar-nav .LinkButtonClicked a {
  background-color: var(--disabled-foreground);
  background-image: none;
  border-color: var(--disabled-foreground);
  border-radius: 6px;
  padding: 6px 16px;
  cursor: default;
  opacity: 0.7;
}

/* Slim variant */
body.sidebar-nav .LinkButton_Slim {
  border-radius: 4px;
  padding: 3px 10px;
}

/* Nested <ins> spacer (asp:LinkButton renders <ins>&nbsp;</ins>) */
body.sidebar-nav .LinkButton ins,
body.sidebar-nav .Secondary ins,
body.sidebar-nav .LinkButtonClicked ins {
  text-decoration: none;
}

/* Focus ring — accessible keyboard focus indicator */
body.sidebar-nav a.LinkButton:focus-visible,
body.sidebar-nav .LinkButton:focus-visible,
body.sidebar-nav input[type="submit"]:focus-visible,
body.sidebar-nav input[type="button"]:focus-visible,
body.sidebar-nav .Secondary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Content hyperlinks — brand teal default (QEN-8776)

   MainWhiteout.css:111 sets `a:link { color: var(--brand-primary) }`, which
   resolves to navy #4F72A4 on refresh pages (the .q88-refresh teal rebind of
   --brand-primary does NOT reach the document root, so plain links rendered
   navy site-wide). This makes brand teal (var(--link), retuned in tokens.css
   under body.sidebar-nav) the default colour for textual hyperlinks in the
   main content region on EVERY refresh page.

   Scoped to `.q88-content` (the layout's main-content wrapper — navigation.css
   §layout) NOT the whole body, so the sidebar (nav#q88Sidebar.q88-sidebar) and
   header (.q88-header), which live OUTSIDE .q88-content, keep their slate
   nav-chrome colours. (An earlier body-wide version clobbered the slate
   sidebar links: `.sidebar-nav .q88-sidebar__link` is only 0,0,2,0.)

   :not() uses a single selector list (CSS L4) so its specificity stays at one
   class — the whole selector is 0,0,4,2, enough to beat MainWhiteout's a:link
   (0,0,1,1) while staying low enough that page-scoped link rules (admin-list,
   application-settings, EditProfile, …) still win where they set a colour.

   Excludes: .LinkButton/.LinkButtonClicked (teal buttons — white text would go
   invisible), [class*="Img-Std"] (icon anchors), [class*="dx-"] (DevExpress
   grid links — carry own theming; also matches .dx-link), .q88-cal-btn-save
   (CalendarControl.ascx LinkButton with CssClass="q88-cal-btn-save" — its
   CssClass replaces the default LinkButton class so the rule above wasn't
   filtering it, repainting the white pill text in --link teal on top of
   the teal background).
   -------------------------------------------------------------------------- */
body.sidebar-nav .q88-content a:link:not(.LinkButton, .LinkButtonClicked, [class*="Img-Std"], [class*="dx-"], .q88-cal-btn-save, .milbros-search-btn-primary),
body.sidebar-nav .q88-content a:visited:not(.LinkButton, .LinkButtonClicked, [class*="Img-Std"], [class*="dx-"], .q88-cal-btn-save, .milbros-search-btn-primary) {
  color: var(--link);
}

body.sidebar-nav .q88-content a:hover:not(.LinkButton, .LinkButtonClicked, [class*="Img-Std"], [class*="dx-"], .q88-cal-btn-save, .milbros-search-btn-primary) {
  color: var(--link-hover, var(--link));
}

/* --- Native checkboxes & radios — brand teal accent (portal-aware) ---
   Re-tint the native checkbox / radio fill with the per-portal primary:
   both portals now resolve to indigo via the semantic --primary/--brand-primary
   chain; raw-teal-600/raw-milbros-teal are legacy primitives no longer wired
   to any active brand token.
   `accent-color` is the lowest-risk approach — it re-tints the fill
   without rewriting checkbox/radio chrome (size, border, focus ring,
   indeterminate state) and degrades gracefully on older browsers.
   Scoped under `body.sidebar-nav` so legacy (non-refresh) pages keep
   the OS accent. Pages that need a bespoke 16×16 dot chassis (e.g.
   questionnaire §9.12.5, milbros-search §13.1.2, EditProfile, terminal-
   vetting) override via `appearance: none` and win over this base rule.

   NOTE on token choice: use `--primary`, NOT `--brand-primary`.
   `--brand-primary` on plain `body.sidebar-nav` resolves to the LEGACY
   navy (#4f72a4) for back-compat and only flips to teal under the
   `.q88-refresh` co-class (Home tab on Q88). `--primary` is rebound to
   teal at `body.sidebar-nav` scope (tokens.css:423) and to Milbros
   teal on Milbros, so it's the reliable cross-portal refresh teal. */
body.sidebar-nav input[type="checkbox"],
body.sidebar-nav input[type="radio"] {
  accent-color: var(--primary);
}

/* --- Pill Toggle Buttons (new — Dashboard|Classic pattern from Figma) --- */
.q88-refresh .q88-btn-toggle-group {
  display: inline-flex;
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--primary);
}

.q88-refresh .q88-btn-toggle {
  padding: 5px 16px;
  border: none;
  background: transparent;
  color: var(--primary);
  cursor: pointer;
  font-weight: 500;
  font-family: var(--font-family);
  font-size: var(--font-size-sm);
}

.q88-refresh .q88-btn-toggle.active,
.q88-refresh .q88-btn-toggle:hover {
  background-color: var(--primary);
  color: var(--primary-foreground);
}

/* --------------------------------------------------------------------------
   3. Module Templates (Cards)
   -------------------------------------------------------------------------- */

/* --- V1: Classic Boxed Module --- */

.q88-refresh .modInnerContainer {
  border: none;
  border-radius: 6px;
  box-shadow: var(--raw-shadow-sm);
  overflow: hidden;
}

.q88-refresh .modInnerContainerIsAlert {
  border-radius: 6px;
  box-shadow: 0 0 0 1px var(--status-error);
}

.q88-refresh .modTitle {
  padding: 8px 12px;
}

.q88-refresh .modSub1 {
  padding: 6px 12px;
  border-bottom: 1px solid var(--border-subtle);
}

.q88-refresh .modMain {
  padding: 12px;
}

.q88-refresh .modFooter2 {
  background-color: var(--card-subtle);
  border-top: 1px solid var(--border-subtle);
  padding: 10px 12px;
}

/* --- V2: Modern Flat Module --- */

.q88-refresh .modV2Title {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
}

.q88-refresh .modV2SubHeader {
  border-bottom-color: var(--border-subtle);
}

.q88-refresh .modV2Main {
  border-radius: 6px;
  box-shadow: var(--raw-shadow-sm);
  padding: 12px;
}

/* --------------------------------------------------------------------------
   4. Alerts / Notifications
   -------------------------------------------------------------------------- */

/* AlertBox uses ModuleTemplate chrome — the module styles above already
   apply. These rules add the status-colored left border pattern. */
.q88-refresh .modInnerContainerIsAlert .modTitle {
  border-left: 4px solid var(--status-error);
}

/* --------------------------------------------------------------------------
   5. Loading Overlay — Processing Request popup (Figma 133:9184)
   --------------------------------------------------------------------------
   Rules moved to /styles/loading-modal.css (QEN-8704) so Blank.master pages
   (iframes that fire LoadingModal on their own async postbacks) can pick up
   the same chrome without pulling in all of components.css. Registered in
   Default.master.cs and Blank.master.cs under the same EnableRefreshedFrontend +
   portal 0/1/2 gate.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   6. Modals
   -------------------------------------------------------------------------- */

/* Page-scroll lock — paired with ShowModal() in Scripts/script.js. When any
   uc:Modal is open, the body gets this class; wheel/touch input scrolls the
   modal body instead of the underlying page. Last-modal-closed logic in
   ShowModal removes the class once the z-index counter returns to baseline,
   so stacked modals (e.g. open Edit Question Answer → open Answer History
   from it) all behave correctly. */
body.q88-modal-open {
  overflow: hidden;
}

/* Keep modal popups position:fixed even after the user drags them. RecenterModalPopup
   sets `position: fixed` on show so the popup's inline left/top are viewport-
   relative; AjaxControlToolkit's PopupDragHandle then writes `position: absolute`
   during drag, which reinterprets those coords as document-origin — combined
   with the page scroll lock above, that parks the popup off-screen with no way
   to scroll the page to reach it. !important beats the DOM-set inline style. */
body.q88-modal-open .modPopPnl {
  position: fixed !important;
}

/* Lift the open modal (panel + dim backdrop) above the sticky header + sidebar.
   `.q88-content` is a stacking context (position:relative + isolation:isolate,
   L1611) at effective root z-index 0 — BELOW the header (z 900) and sidebar
   (z 800). AjaxControlToolkit gives the MPE panel/backdrop z 100001/10000, but
   those are TRAPPED inside .q88-content's context (see officer-matrix-vessel.css
   §14.9), so the header painted over the modal's top edge. Most visible on the
   Edit Observation modal (ACT ModalPopupExtender, pinned to top:16px): its title
   + close-X slid under the ~56px header band, and the backdrop couldn't dim the
   sidebar (which lives outside .q88-content). Lifting the whole content context
   to z 1000 while a modal is open puts panel + backdrop above header/sidebar,
   and reverts on close.

   Two open-state gates, one per modal mechanism on refresh pages:
   - uc:Modal (Modal.ascx) adds body.q88-modal-open via ShowModal() (script.js).
   - The Edit Observation modal is a raw ACT MPE that does NOT add that class, so
     gate on its backdrop being shown. ACT toggles the backgroundElement's inline
     `display` (none when closed, absent when open) — same proven open-detection
     pattern as officer-matrix-vessel §14.9 / the mpePerson scroll-lock. */
body.q88-modal-open .q88-content,
body.sidebar-nav:has(#mpeEditObservation_backgroundElement:not([style*="display: none"]):not([style*="display:none"])) .q88-content {
  z-index: 1000;
}

/* Container — rounded corners and shadow */
.q88-refresh .modPopupTbl {
  border-radius: 8px;
  box-shadow: var(--raw-shadow-xl);
  overflow: hidden;
}

/* Hide decorative corner images */
.q88-refresh .modPopupTbl .leftCornerIcon,
.q88-refresh .modPopupTbl .rightCornerIcon {
  display: none;
}

/* Header bar — slightly taller, better padding */
.q88-refresh .modPopupTbl .hdrTblBar {
  height: 40px;
  padding: 0 12px;
}

/* Close button — hide red GIF, add CSS X */
.q88-refresh .modPopupTbl .hdrTblBar a[id$="_lnkClose"] img {
  display: none;
}

.q88-refresh .modPopupTbl .hdrTblBar a[id$="_lnkClose"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 4px;
  color: var(--primary-foreground);
  font-size: 18px;
  text-decoration: none;
  opacity: 0.8;
}

.q88-refresh .modPopupTbl .hdrTblBar a[id$="_lnkClose"]::after {
  content: '\00D7';  /* multiplication sign (×) */
  font-size: 20px;
  line-height: 1;
}

.q88-refresh .modPopupTbl .hdrTblBar a[id$="_lnkClose"]:hover {
  opacity: 1;
  background: rgba(255, 255, 255, 0.15);
}

/* Content — more breathing room */
.q88-refresh .modPopupTbl .modPopContent {
  padding: 16px;
}

/* Footer — lighter, with separator */
.q88-refresh .modPopupTbl .modPopFooter {
  background-color: var(--card-subtle);
  border-top: 1px solid var(--border-subtle);
  padding: 12px 16px;
}

/* Top cap — remove extra spacing */
.q88-refresh .modPopupTbl .modPopContentTop {
  height: 0;
  display: none;
}

/* --------------------------------------------------------------------------
   7. Content Tabs
   -------------------------------------------------------------------------- */

/* Two scopes share this tab chrome (same pattern as §8 popup menus below):
   - .q88-refresh        — pages with the explicit refresh wrapper
   - body.page-viewship  — EVERY ViewShip vessel-view request (all tabs: Vessel Data /
     Documents / Dwt-Draft / AIS / USCG / Photos) + the cross-portal DesktopDefault.aspx?i=
     redirect target. Wired in Default.Master.cs. This flow does NOT carry .q88-refresh,
     so without the extra scope the ContentTabLink strip fell back to the legacy sprite
     (contentTabBG.png) + navy #4f72a4 bold text, standing out against the slate/teal
     refresh. The markup is identical (a.ContentTabLink > span.ContentTab|ContentTabOn >
     span.Left + span.Middle), so the same rules apply verbatim. (Originally scoped to
     page-questionnaire = Vessel-Data tab only; broadened to page-viewship so the sister
     sub-view tabs, which lack page-questionnaire, also get the refreshed tab strip.) */

/* Override sprite-based tab rendering with CSS border-bottom indicators */
.q88-refresh .ContentTab,
.q88-refresh .ContentTabOn,
body.page-viewship .ContentTab,
body.page-viewship .ContentTabOn {
  border-bottom: 3px solid transparent;
}

/* Remove sprite backgrounds from tab segments */
.q88-refresh .ContentTab .Left,
.q88-refresh .ContentTab .Right,
.q88-refresh .ContentTabOn .Left,
.q88-refresh .ContentTabOn .Right,
body.page-viewship .ContentTab .Left,
body.page-viewship .ContentTab .Right,
body.page-viewship .ContentTabOn .Left,
body.page-viewship .ContentTabOn .Right {
  background-image: none;
  width: 0;
  display: none;
}

.q88-refresh .ContentTab .Middle,
.q88-refresh .ContentTabOn .Middle,
body.page-viewship .ContentTab .Middle,
body.page-viewship .ContentTabOn .Middle {
  background-image: none;
  height: auto;
  padding: 8px 16px;
  line-height: normal;
  /* Typography (QEN-8776): the legacy ContentTabLink renders a cramped 12px
     label in flat #666. Lift to the refresh nav size/weight/colour so the tab
     strip reads like the sidebar (14px) instead of fine print. Inactive =
     medium 500 slate; the .ContentTabOn override below bumps active → 600 +
     --foreground. */
  font-size: 14px;
  font-weight: var(--font-weight-medium, 500);
  color: var(--muted-foreground);
}

/* Active tab — teal bottom border */
.q88-refresh .ContentTabOn,
body.page-viewship .ContentTabOn {
  border-bottom-color: var(--primary);
}

.q88-refresh .ContentTabOn .Middle,
body.page-viewship .ContentTabOn .Middle {
  color: var(--foreground);
  font-weight: 600;
}

/* Hover state */
.q88-refresh .ContentTabLink:hover .ContentTab,
body.page-viewship .ContentTabLink:hover .ContentTab {
  border-bottom-color: var(--border);
}

.q88-refresh .ContentTabLink:hover .ContentTab .Middle,
body.page-viewship .ContentTabLink:hover .ContentTab .Middle {
  color: var(--foreground);
}

/* --------------------------------------------------------------------------
   7.a Questionnaire-flow header action links (QEN-8776, 2026-06-08)

   ViewShip.aspx renders toolbar actions as legacy `a.linkWHover` links in the
   ModuleTemplateV2 header: "Vessel Search" in .modV2TRight (title row) and
   "Print Q88" / "Email Q88" in .modV2SubHeader (tab row). Legacy paints them
   navy #003366, 700 bold, 3px padding — wrong colour and visually cramped/
   misaligned against the tab strip. Re-skin to teal text links (per the
   "refresh links must be teal, not blue" standard), medium weight, centred in
   the row, with a subtle hover. Scoped to the two header containers so card-body
   links are untouched.
   -------------------------------------------------------------------------- */
body.page-viewship .modV2SubHeader .linkWHover,
body.page-viewship .modV2SubHeader a.linkWHover:link,
body.page-viewship .modV2SubHeader a.linkWHover:visited,
body.page-viewship .modV2TRight .linkWHover,
body.page-viewship .modV2TRight a.linkWHover:link,
body.page-viewship .modV2TRight a.linkWHover:visited {
  color: var(--primary) !important;                    /* teal #0d9488 in-scope — !important beats MainWhiteout's a:link navy */
  font-weight: var(--font-weight-medium, 500);
  font-size: 13px;
  padding: 6px 8px;
  border: 0;
  border-radius: 6px;
  vertical-align: middle;
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease;
}

body.page-viewship .modV2SubHeader .linkWHover:hover,
body.page-viewship .modV2TRight .linkWHover:hover {
  color: var(--button-primary-hover, #0b7c70) !important;
  background-color: var(--surface-accent-hover, #f0fdfa);
  text-decoration: none;
}

/* --------------------------------------------------------------------------
   7.b Align the modV2 header + footer with the inset q88-card (QEN-8776, 2026-06-08)

   The View-flow card (#pnlQuestionnaires) is inset to `calc(100% - 96px)` and
   centred (48px each side), but the ModuleTemplateV2 title row, tab strip and
   footer span the FULL ContentPane width — so the right-aligned action links
   ("Vessel Search" / "Print Q88" / "Email Q88") AND the footer "Top" button
   overshoot the card's right edge by ~48px (and the vessel name / tabs hang the
   same ~48px past its left edge). Give those containers the card's width +
   centring so the whole header/footer column lines up with the card.
   Scoped to body.page-viewship via the OUTER module's id-suffixes (_m_pnlTitle =
   modV2TitleContainer, _m_pnlSubHeader = tab strip + action links, _m_pnlFooter =
   Top button) so it aligns the shared chrome on EVERY tab WITHOUT touching the
   nested sub-module modV2 chrome on the DWT / AIS / USCG tabs (those carry their
   own _cpMain_/_ctl07_ modV2TitleContainer/SubHeader which must NOT be inset).
   -------------------------------------------------------------------------- */
body.page-viewship [id$='_m_pnlTitle'],
body.page-viewship [id$='_m_pnlSubHeader'],
body.page-viewship [id$='_m_pnlFooter'] {
  display: block;                /* modV2TitleContainer ships as inline-block (in a <td>) → margin:auto computes to 0 and it stays left; block lets the auto margins centre it like the subheader/footer */
  width: calc(100% - 96px);
  margin-left: auto;
  margin-right: auto;
  box-sizing: border-box;
}

/* --------------------------------------------------------------------------
   7.c Vessel-name title — Create-parity (QEN-8776, 2026-06-08)

   The View flow prints the vessel name in the legacy ModuleTemplateV2 title
   (div.modV2Title > span[id$='_m_lblVessel']), which MainWhiteout.css paints
   navy (var(--brand-accent) #2D3663) at 20px / weight 300 / non-italic. The
   Create flow prints the vessel name in the refreshed card header
   (h2.q88-tophdr__title, 16px / 600 / #0f0f0f — questionnaire.css §1/§…). The
   user wants the View vessel name to read identically to Create, so match the
   Create header's text styling here. The inner span carries no class and
   inherits these values from the div.
   Scoped to body.page-viewship + the OUTER vessel-name id-suffix (_m_pnlTitleLeft)
   so it styles the vessel name on EVERY tab but NOT the nested sub-module titles
   (USCG "USCG PSIX", DWT/AIS module titles, which keep their own styling).
   Specificity (0,3,1) beats MainWhiteout's `.modV2 .modV2Title` (0,2,0) without
   !important; font-family already resolves to Inter and font-style/padding-left
   are already normal/0 in the legacy rule.
   -------------------------------------------------------------------------- */
body.page-viewship .modV2Title[id$='_m_pnlTitleLeft'] {
  font-size: 16px;
  font-weight: 600;
  line-height: 24px;
  color: #0f0f0f;
}

/* --------------------------------------------------------------------------
   8. Popup Menus

   QEN-8801: promoted to body.sidebar-nav so EVERY uc:PopupMenu under the
   refresh skin shares the same dropdown chrome ("all 'more' menus follow the
   same dropdown design"). The original two scopes are kept for safety:
   - .q88-refresh  — pages with the explicit refresh wrapper
   - body.page-questionnaire — Create/View Questionnaire flow, which doesn't
     use .q88-refresh but renders the same `popMenuActions` 3-dot menu in
     the top-right of the q88-card (Contact Details / Officer Matrix
     Compliance / Questionnaire History / Vetting Details). Without this
     extra scope the menu fell back to the legacy ad-hoc chrome (flat grey
     border, no radius, no shadow, 12px font, no hover state).
   Per-page copies of the same pattern (certificates.css page-certificate-
   detail, inspection-container.css §22, editQuestionAnswerPopup.css) load
   AFTER components.css, so on those pages they keep winning ties — values
   are identical, so behavior is unchanged there.
   -------------------------------------------------------------------------- */

body.sidebar-nav .popupMenuV2,
.q88-refresh .popupMenuV2,
body.page-questionnaire .popupMenuV2 {
  border-radius: 8px;
  box-shadow: var(--raw-shadow-lg);
  border: 1px solid var(--border-subtle);
  background-image: none;
  background-color: var(--background);
  overflow: hidden;
  padding: 4px 0;
  /* never inherit text-align from a right-aligned trigger cell — long items
     would right-align and clip their left edge under overflow:hidden */
  text-align: left;
  /* Legacy markup pins these popups to a fixed inline height (e.g. height:20px/
     40px) which, with overflow:hidden, clips the menu items. Let the popup size
     to its content. !important beats the inline style. */
  height: auto !important;
  min-height: 0 !important;
}

body.sidebar-nav .popupMenuV2 .popupMenuItem,
.q88-refresh .popupMenuV2 .popupMenuItem,
body.page-questionnaire .popupMenuV2 .popupMenuItem {
  height: auto;
  padding: 6px 12px;
  border-radius: 0;
  /* Undo MainWhiteout's `.popupMenuItem { height: 20px; overflow: hidden }`
     clip so padded/wrapped labels stay fully visible (the certificate-detail
     "cut off labels" trap). */
  overflow: visible;
  /* Re-assert wrap: white-space is inherited, and some host pages impose
     `nowrap` on an ancestor of this popup (e.g. milbros-booking-list.css's
     blanket `.BookingDetails td { white-space: nowrap }`, which leaks in
     because the popup panel renders as a DOM descendant of that `<td>`
     despite being visually detached via `position:absolute`). Without this,
     long items don't wrap and get silently clipped by the fixed-width panel
     + `overflow:hidden` above — the Milbros "Copy From" cut-off-names bug. */
  white-space: normal;
}

body.sidebar-nav .popupMenuV2 .popupMenuItem:hover,
.q88-refresh .popupMenuV2 .popupMenuItem:hover,
body.page-questionnaire .popupMenuV2 .popupMenuItem:hover {
  background-color: var(--surface-accent-hover);
}

body.sidebar-nav .popupMenuV2 .popupMenuItem .popupMenuItemContent,
.q88-refresh .popupMenuV2 .popupMenuItem .popupMenuItemContent,
body.page-questionnaire .popupMenuV2 .popupMenuItem .popupMenuItemContent {
  /* Reset the legacy `position: absolute; top: 50%` from MainWhiteout.css
     — that trick is no longer needed once .popupMenuItem uses padding-driven
     auto-height. Without this reset the inner content is taken out of flow
     and every menu item collapses to 0 visible content, so the 4 entries
     stack in a 48px-tall menu where they should occupy ~36px each. */
  position: static;
  top: auto;
  margin: 0;
  padding: 0 8px;
}

/* Menu-item text — one colour across every "more" menu (QEN-8801).
   Without this, item anchors fell back to each page's link colour (navy
   MainWhiteout a:link on grids, teal .q88-content rule on questionnaire),
   so the same menu looked different per page. Dark text matches the
   certificate-detail reviewed canon (certificates.css ~L1016) and the
   shadcn dropdown reference. The :link/:visited/:hover forms reach (0,4,2),
   tying the §"content links teal" rule at L440 — this block is later in the
   file, so it wins the tie inside menus only. Per-page !important copies
   (certificate-detail) still win. */
body.sidebar-nav .popupMenuV2 .popupMenuItem a,
body.sidebar-nav .popupMenuV2 .popupMenuItem a:link,
body.sidebar-nav .popupMenuV2 .popupMenuItem a:visited,
body.sidebar-nav .popupMenuV2 .popupMenuItem a:hover,
body.sidebar-nav .popupMenuV2 .popupMenuItemContent a,
body.sidebar-nav .popupMenuV2 .popupMenuItemContent a:link,
body.sidebar-nav .popupMenuV2 .popupMenuItemContent a:visited,
body.sidebar-nav .popupMenuV2 .popupMenuItemContent a:hover {
  color: var(--text-primary);
  text-decoration: none;
}

/* Divider between menu groups */
body.sidebar-nav .popupMenuV2 .Spacer,
.q88-refresh .popupMenuV2 .Spacer,
body.page-questionnaire .popupMenuV2 .Spacer {
  border-top: 1px solid var(--border-subtle);
  margin: 4px 0;
  height: 0;
  overflow: hidden;
}

body.sidebar-nav .popupMenuV2 .Spacer img,
.q88-refresh .popupMenuV2 .Spacer img,
body.page-questionnaire .popupMenuV2 .Spacer img {
  display: none;
}

/* Scrollable variant — styled scrollbar. Thumb uses --border-strong (not the
   near-invisible --border, #e5e5e5) to match every other scrollable popup
   added in this refresh (observations-edit.css, popupQuestionnaireSide.css,
   MilbrosCommodityRefresh.css) — with --border it blended into the white
   track so the list (e.g. Manage Users "Columns" picker) looked like it
   ended at the viewport edge instead of being scrollable (QEN-8831). */
body.sidebar-nav .popupMenuV2ScollableContainer,
.q88-refresh .popupMenuV2ScollableContainer,
body.page-questionnaire .popupMenuV2ScollableContainer {
  border-radius: 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

body.sidebar-nav .popupMenuV2ScollableContainer::-webkit-scrollbar,
.q88-refresh .popupMenuV2ScollableContainer::-webkit-scrollbar,
body.page-questionnaire .popupMenuV2ScollableContainer::-webkit-scrollbar {
  width: 6px;
}

body.sidebar-nav .popupMenuV2ScollableContainer::-webkit-scrollbar-track,
.q88-refresh .popupMenuV2ScollableContainer::-webkit-scrollbar-track,
body.page-questionnaire .popupMenuV2ScollableContainer::-webkit-scrollbar-track {
  background: transparent;
}

body.sidebar-nav .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb,
.q88-refresh .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb,
body.page-questionnaire .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb {
  background-color: var(--border-strong);
  border-radius: 3px;
}

body.sidebar-nav .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb:hover,
.q88-refresh .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb:hover,
body.page-questionnaire .popupMenuV2ScollableContainer::-webkit-scrollbar-thumb:hover {
  background-color: var(--text-tertiary);
}

/* --------------------------------------------------------------------------
   9. Calendar
   -------------------------------------------------------------------------- */

/* Calendar popup container — broadened from .q88-refresh to body.sidebar-nav so
   Milbros refresh pages (PortalId 2) get the same popup chrome as Q88 refresh. */
body.sidebar-nav .CalendarDisplay .ajax__calendar_container {
  border-radius: 8px;
  box-shadow: var(--raw-shadow-lg);
  border: 1px solid var(--border-subtle);
  overflow: hidden;
}

/* Calendar header (month/year navigation) */
body.sidebar-nav .CalendarDisplay .ajax__calendar_header {
  background-color: var(--primary);
  padding: 8px;
}

/* Day cells — hover highlight. The hover bg is dark (teal/yellow accent in
   refresh), so the day text needs to flip to --primary-foreground (white) or
   it reads unreadable against the new fill. */
body.sidebar-nav .CalendarDisplay .ajax__calendar_day:hover {
  background-color: var(--grid-row-focus);
  color: var(--primary-foreground);
  border-radius: 4px;
}

/* Selected day */
body.sidebar-nav .CalendarDisplay .ajax__calendar_active {
  background-color: var(--primary);
  color: var(--primary-foreground);
  border-radius: 4px;
}

/* Today indicator — primary-coloured border on right/bottom/left only.
   No `border-top` anywhere on this rule. */
body.sidebar-nav .CalendarDisplay .ajax__calendar_today {
  border: 1px solid var(--primary);
  border-radius: 4px;
}

/* --------------------------------------------------------------------------
   10. Grid Overrides (DevExpress)
   -------------------------------------------------------------------------- */

/* Container — rounded corners and subtle shadow */
.q88-refresh .dxgvControl {
  border-radius: 8px !important;
  box-shadow: var(--raw-shadow-sm) !important;
  overflow: hidden;
}

/* Header — lighter approach: subtle bottom border instead of dark fill */
.q88-refresh .dxgvHeader {
  background: var(--card-subtle) !important;
  border-bottom: 2px solid var(--accent) !important;
}

.q88-refresh .dxgvHeader td,
.q88-refresh .dxgvHeader .tblColHeader td a {
  color: var(--foreground) !important;
}

/* Row hover — smooth transition, teal tint */
.q88-refresh .dxgvDataRow td {
  transition: background-color 0.15s ease;
}

.q88-refresh .dxgvDataRow:hover td {
  background-color: var(--grid-row-focus) !important;
  border-top-color: transparent !important;
}

/* Focus/selected row — teal tint instead of yellow */
.q88-refresh .GridRowFocus,
.q88-refresh .GridRowFocus TD {
  background-color: var(--grid-row-focus) !important;
}

/* Alt-row — flatten to uniform or very subtle alternation */
.q88-refresh .dxgvDataRow_Version3 td {
  background-color: var(--background) !important;
}

.q88-refresh .dxgvAlternateRow td {
  background-color: var(--card-subtle) !important;
}

/* Pager — current page with teal highlight */
.q88-refresh .GridPager .dxp-current {
  background-color: var(--primary) !important;
  color: var(--primary-foreground) !important;
  border-radius: 4px !important;
  padding: 2px 8px !important;
}

.q88-refresh .GridPager a:hover {
  color: var(--primary) !important;
}

/* Filter indicators — CSS chip pills replacing GridFilterBG.png */
.q88-refresh .FilterAppliedItem {
  background-color: var(--raw-gray-600) !important;
  background-image: none !important;
  color: var(--primary) !important;
  border-radius: 12px !important;
  padding: 2px 10px !important;
  font-size: var(--font-size-xs) !important;
  border: 1px solid var(--primary) !important;
}

.q88-refresh .FilterAppliedItemAll {
  background-color: var(--card-subtle) !important;
  background-image: none !important;
  border-radius: 12px !important;
  padding: 2px 10px !important;
  border: 1px solid var(--border) !important;
}

/* Grid sort icon area — ensure visibility on lighter header */
.q88-refresh .dxgvHeader .dxgvSortedHeaderContent {
  color: var(--primary) !important;
}

/* --------------------------------------------------------------------------
   10b. Global "no stray table frame" pass (QEN-8776)
   Refresh cards already provide the outer border + radius, so tables and grids
   must NOT paint their own outer box border on top of the card. Scoped to
   body.sidebar-nav (not .q88-refresh) so it reaches every refreshed page,
   including Dry + Milbros. Only the OUTER FRAME is removed — header underlines
   and row separators live on the cells (td border-bottom) and stay intact.
   -------------------------------------------------------------------------- */

/* DevExtreme dxDataGrid: the light theme paints a vertical frame border on the
   section wrappers (.dx-datagrid-headers / -rowsview / -total-footer). Strip
   left + right. Pages that deliberately frame the grid set their border on the
   separate .dx-datagrid.dx-datagrid-borders element (e.g. body.page-admin-grid)
   — a different element, so that intentional frame is preserved. */
body.sidebar-nav .dx-datagrid-headers,
body.sidebar-nav .dx-datagrid-rowsview,
body.sidebar-nav .dx-datagrid-total-footer {
  border-left-width: 0 !important;
  border-right-width: 0 !important;
}

/* Legacy .StdTable.BorderAll: the base rule (MainWhiteout/Main .BorderAll)
   paints a 1px solid !important frame on the table element. Remove that outer
   frame (needs !important to beat the base). The per-page refresh skins add row
   separation via td border-bottom, which is untouched, so rows + the header
   underline keep their dividers. */
body.sidebar-nav table.StdTable.BorderAll {
  border-width: 0 !important;
}

/* --------------------------------------------------------------------------
   11. FleetVessel
   -------------------------------------------------------------------------- */

/* Fleet/Vessel container row above grid */
.q88-refresh .grdViewRowTd {
  padding: 8px 12px;
  border-radius: 6px 6px 0 0;
}

.q88-refresh .grdViewRowTd select {
  border-radius: 6px;
  border: 1px solid var(--border);
  padding: 4px 8px;
  font-family: var(--font-family);
  font-size: var(--font-size-sm);
  background-color: var(--input-background);
  color: var(--foreground);
}

.q88-refresh .grdViewRowTd select:focus {
  border-color: var(--primary);
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

.q88-refresh .grdViewRowTd label {
  color: var(--secondary-foreground);
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* --------------------------------------------------------------------------
   12. ComboBox
   -------------------------------------------------------------------------- */

/* Style the input and dropdown elements used by ComboBox.ascx */
.q88-refresh .NormalTextBox {
  border-radius: 6px;
  border: 1px solid var(--border);
  padding: 4px 8px;
  font-family: var(--font-family);
}

.q88-refresh .NormalTextBox:focus {
  border-color: var(--primary);
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

/* ComboBox and Calendar share NormalTextBox — this is fine, both get
   the same clean input field styling */

/* --------------------------------------------------------------------------
   12.5 Q88 canonical dropdown skin (DESIGN.md §9.6 ⭐)

   Single source of truth for dropdown triggers across the refreshed Q88 +
   Milbros portal. Lifted out of createQuestionnaire.css (which had this
   skin scoped to [id$="modQSelect_divMod"]) so every refreshed page
   inherits the same look without per-page CSS.

   Applies to:
     <select> / <asp:DropDownList>          (native; legacy class .NormalTextBox/.NormalBox kept for spec defense)
     ComboBox.ascx (.cbArrow input)         (AjaxControlToolkit AutoCompleteExtender host)

   Does NOT apply to:
     DevExtreme .dx-selectbox               — separate override block needed (TODO: add when ready)
     §9.6.4 Date Picker (h:36)              — different size/icon, kept page-scoped
     §9.6.5 InputGroup with unit pill       — different anatomy

   Scoping: body.sidebar-nav only. Legacy top-nav pages keep their old skin.
   Specificity defence: list `select.NormalTextBox` / `select.NormalBox` /
   `input.NormalTextBox.cbArrow` explicitly so legacy class selectors don't
   beat the bare-tag selectors and trap padding-right at 12px (would cause
   text to overlap the chevron at long option labels). See DESIGN.md §9.6
   "CSS specificity gotcha" callout for the full rationale.

   Rollback: delete this section → pages fall back to legacy MainWhiteout.css
   /grid.css / portal CSS. Create Questionnaire keeps its own copy via the
   [id$="modQSelect_divMod"] scope.
   -------------------------------------------------------------------------- */

/* Base trigger skin — typography / border / radius / bg apply to every
   <select> + ComboBox input flavour, including multi-row list boxes (so a
   multiselect still inherits the refresh chrome). Height is handled
   separately below because multiselects need their native taller layout. */
body.sidebar-nav select,
body.sidebar-nav select.NormalTextBox,
body.sidebar-nav select.NormalBox,
body.sidebar-nav input.cbArrow,
body.sidebar-nav input.NormalTextBox.cbArrow {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px !important;
    font-weight: 400;
    line-height: 20px;
    color: var(--text-primary) !important;
    padding-top: 4px !important;
    padding-bottom: 4px !important;
    padding-left: 12px !important;
    /* padding-right set per kind below — selects/cbArrow get 32 to clear chevron */
    border: 1px solid var(--border-default) !important;
    border-radius: 8px !important;
    background-color: #ffffff !important;
    box-sizing: border-box;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}

/* h:32 trigger height — single-row selects + the ComboBox input only.
   `:not([multiple])` excludes multi-row list boxes (which need the native
   listbox height = N rows). */
body.sidebar-nav select:not([multiple]),
body.sidebar-nav select.NormalTextBox:not([multiple]),
body.sidebar-nav select.NormalBox:not([multiple]),
body.sidebar-nav input.cbArrow,
body.sidebar-nav input.NormalTextBox.cbArrow {
    height: 32px !important;
    min-height: 32px;
}

/* Native <select> — kill OS arrow, draw our chevron via background SVG.
   Skip multi-row list boxes: appearance:none + chevron would paint a fake
   down-arrow on the corner of a multi-row listbox where no popup opens. */
body.sidebar-nav select:not([multiple]),
body.sidebar-nav select.NormalTextBox:not([multiple]),
body.sidebar-nav select.NormalBox:not([multiple]) {
    appearance: none !important;
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    padding-right: 32px !important;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>") !important;
    background-repeat: no-repeat !important;
    background-position: right 10px center !important;
    background-size: 16px 16px !important;
}

/* IE-era pseudo for the native expand arrow */
body.sidebar-nav select::-ms-expand {
    display: none !important;
}

/* ComboBox.ascx searchable input — same chevron, mirroring select */
body.sidebar-nav input.cbArrow,
body.sidebar-nav input.NormalTextBox.cbArrow {
    padding-right: 32px !important;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>") !important;
    background-repeat: no-repeat !important;
    background-position: right 10px center !important;
    background-size: 16px 16px !important;
    background-color: #ffffff !important;
    cursor: pointer;
}

/* Focus state — teal border + soft glow */
body.sidebar-nav select:focus,
body.sidebar-nav select.NormalTextBox:focus,
body.sidebar-nav select.NormalBox:focus,
body.sidebar-nav input.cbArrow:focus,
body.sidebar-nav input.NormalTextBox.cbArrow:focus {
    outline: none;
    border-color: var(--primary) !important;
    box-shadow: 0 0 0 2px rgba(var(--primary-tint), 0.15);
}

/* Placeholder colour */
body.sidebar-nav select::placeholder,
body.sidebar-nav input.cbArrow::placeholder {
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   12.5.1 Native <select> popover-shim (DESIGN.md §9.6.1 open state)

   OS-rendered native <select> popups are unstylable, so SelectShim.js
   replaces them with a styled <ul role="listbox"> overlay. The popover
   mirrors the AjaxControlToolkit autocomplete completion list defined
   in createQuestionnaire.css §9.6.6 (radius 8, soft shadow, hover
   #f1f5f9) so the closed and open states share the same visual
   language regardless of which control type rendered the trigger.

   The popover is appended to <body>, positioned with `position: fixed`,
   so it isn't constrained by ancestor `overflow: hidden`. Z-index sits
   above page content but below header/sidebar (header=900, sidebar=800).
   We use 1000 — page content has no z-index, modals are 100001+.

   Open-state trigger: chevron flips to point up via background-image
   swap on `body.sidebar-nav select.q88-select--open`. Border picks up
   the focus colour because :focus is already on the select.
   -------------------------------------------------------------------------- */

/* Chevron flip while open */
body.sidebar-nav select.q88-select--open {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%230d9488' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='18 15 12 9 6 15'/></svg>") !important;
}

/* Popover container — mirrors §9.6.6 completion list */
.q88-select-popover {
    list-style: none;
    margin: 0;
    padding: 4px;
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    box-shadow:
        0 4px 6px -1px rgba(0, 0, 0, 0.1),
        0 2px 4px -2px rgba(0, 0, 0, 0.1);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px;
    line-height: 20px;
    color: #0f172a;
    z-index: 1000;
    overflow-y: auto;
    overflow-x: hidden;
    /* position / top / left / max-height set by SelectShim.js */
}

.q88-select-popover__option {
    padding: 6px 8px;
    border: 1px solid transparent;
    border-radius: 6px;
    color: #000000;
    cursor: pointer;
    line-height: 20px;
    min-height: 20px;                /* empty (null) option reserves a full row */
    /* ellipsis for very long option text */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.q88-select-popover__option--hover {
    background-color: #f1f5f9;
    border-color: #e2e8f0;
}

.q88-select-popover__option--selected {
    background-color: #e2e8f0;
    border-color: #e2e8f0;
}

/* When the currently-selected option is also the active highlight,
   keep the highlight tint so the user sees focus moved off it. */
.q88-select-popover__option--selected.q88-select-popover__option--hover {
    background-color: #cbd5e1;
}

.q88-select-popover__option--disabled {
    color: #94a3b8;
    cursor: not-allowed;
}

.q88-select-popover__option--disabled.q88-select-popover__option--hover {
    background-color: transparent;
    border-color: transparent;
}

/* Optgroup label rows — non-selectable, used as visual section header. */
.q88-select-popover__group {
    padding: 6px 8px 2px 8px;
    font-size: 12px;
    font-weight: 600;
    color: #475569;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    cursor: default;
}

/* Dark mode parity (Phase 4 token system).
   Tokens are scoped to body[data-theme="dark"] elsewhere; we read the
   matching surface tokens here so the popover follows theme. */
body[data-theme="dark"] .q88-select-popover {
    background: var(--surface-raised, #1e293b);
    border-color: var(--border-input, #334155);
    color: var(--text-primary, #f1f5f9);
}

body[data-theme="dark"] .q88-select-popover__option {
    color: var(--text-primary, #f1f5f9);
}

body[data-theme="dark"] .q88-select-popover__option--hover {
    background-color: var(--surface-hover, #334155);
    border-color: var(--border-input, #475569);
}

body[data-theme="dark"] .q88-select-popover__option--selected {
    background-color: var(--surface-active, #475569);
    border-color: var(--border-input, #475569);
}

body[data-theme="dark"] .q88-select-popover__group {
    color: var(--text-muted, #94a3b8);
}

/* --------------------------------------------------------------------------
   12.5.2 Custom <dl>.dropDownCusGrp widget (DESIGN.md §9.6.8)

   Legacy jQuery-driven dropdown rendered by GridViewSelector.ascx and
   DropDownListGrouped.ascx. Source <select> stays in DOM for postback;
   the visible widget is a sibling <dl class="dropDownCusGrp"> with:
     <dt><a>caption<span class="value">id</span></a></dt>
     <dd><ul><li><a class="jqCusDdlText">option</a></li>...</ul></dd>

   We re-skin the same way native <select> + cbArrow are re-skinned in
   §12.5: 32h, 1px #e2e8f0 border, radius 8, white bg, Inter 14, trailing
   chevron SVG. Open list mirrors .q88-select-popover (§12.5.1) so the
   custom widget reads identically to native + cbArrow at every state.

   Default trigger width 170px matches the FleetVessel / GridViewSelector
   pattern. DropDownListGrouped.ascx writes inline style="width:Npx" per
   instance — inline always wins, so per-page widths still work.

   The page-grid #_pnlTitleLeft table-reset (legacy IE-era <table> wrapper
   inside each <li>) lives in grid.css since it is page-grid specific.
   -------------------------------------------------------------------------- */

body.sidebar-nav .dropDownCusGrp {
    display: inline-block;
    margin: 0;
    padding: 0;
    width: 170px;
    height: 32px;
    vertical-align: middle;
    box-sizing: border-box;
}

body.sidebar-nav .dropDownCusGrp dt {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 32px;
}

body.sidebar-nav .dropDownCusGrp dt a {
    display: block;
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    height: 32px;
    margin: 0;
    padding: 6px 32px 6px 12px;
    border: 1px solid #e2e8f0 !important;
    border-radius: 8px !important;
    background-color: #ffffff !important;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>") !important;
    background-repeat: no-repeat !important;
    background-position: right 10px center !important;
    background-size: 16px 16px !important;
    color: #0f172a !important;
    font-family: Inter, system-ui, -apple-system, sans-serif;
    font-size: 14px !important;
    font-weight: 400 !important;
    line-height: 20px;
    text-decoration: none !important;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: border-color 150ms ease, box-shadow 150ms ease;
}

body.sidebar-nav .dropDownCusGrp dt a:hover,
body.sidebar-nav .dropDownCusGrp dt a:focus {
    outline: none;
    border-color: var(--primary) !important;
    color: #0f172a !important;
    box-shadow: 0 0 0 2px rgba(var(--primary-tint), 0.15);
}

/* JS stamps <span class="value">hash</span> next to caption — must hide */
body.sidebar-nav .dropDownCusGrp dt a .value,
body.sidebar-nav .dropDownCusGrp dd .value {
    display: none !important;
}

/* DropDownListGrouped.ascx adds .dropDownCusGrpDisabled when source DDL is empty */
body.sidebar-nav .dropDownCusGrp dt a.dropDownCusGrpDisabled {
    background-color: #f1f5f9 !important;
    color: #94a3b8 !important;
    cursor: not-allowed;
}

/* Open list — mirrors .q88-select-popover from §12.5.1 */
body.sidebar-nav .dropDownCusGrp dd {
    margin: 0;
    position: absolute;
    z-index: 1000;
}

body.sidebar-nav .dropDownCusGrp dd ul {
    list-style: none;
    background: #ffffff;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.08);
    padding: 4px 0;
    margin: 4px 0 0;
    min-width: 220px;
    max-height: 400px;
    overflow-y: auto;
}

body.sidebar-nav .dropDownCusGrp dd ul li {
    padding: 0;
    height: auto;
    line-height: normal;
}

body.sidebar-nav .dropDownCusGrp dd ul .jqCusDdlText {
    display: block;
    padding: 8px 12px;
    line-height: 20px;
    min-height: 20px;
    color: #0f172a !important;
    /* !important needed: legacy GridViewSelector wraps each item in
       <table><tr><td>, and Main.css resets font-family on <table> which
       breaks inheritance on the inner <a>. Trigger <dt a> doesn't hit
       this since it isn't table-wrapped. */
    font-family: Inter, system-ui, -apple-system, sans-serif;
    font-size: 14px !important;
    font-weight: 400 !important;
    text-decoration: none !important;
    white-space: nowrap;
}

body.sidebar-nav .dropDownCusGrp dd ul li:hover .jqCusDdlText {
    background: #f1f5f9;
}

/* Section labels — <b>Company Views</b>, <b>User Views</b>, <b>System Views</b> */
body.sidebar-nav .dropDownCusGrp dd ul b {
    display: block;
    padding: 6px 12px 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #475569;
}

/* Dark mode parity */
body[data-theme="dark"].sidebar-nav .dropDownCusGrp dt a {
    background-color: var(--surface-raised, #1e293b) !important;
    border-color: var(--border-input, #334155) !important;
    color: var(--text-primary, #f1f5f9) !important;
}

body[data-theme="dark"].sidebar-nav .dropDownCusGrp dt a:hover,
body[data-theme="dark"].sidebar-nav .dropDownCusGrp dt a:focus {
    border-color: var(--primary, #14b8a6) !important;
}

body[data-theme="dark"].sidebar-nav .dropDownCusGrp dd ul {
    background: var(--surface-raised, #1e293b);
    border-color: var(--border-input, #334155);
}

body[data-theme="dark"].sidebar-nav .dropDownCusGrp dd ul .jqCusDdlText {
    color: var(--text-primary, #f1f5f9);
}

body[data-theme="dark"].sidebar-nav .dropDownCusGrp dd ul li:hover .jqCusDdlText {
    background: var(--surface-hover, #334155);
}

body[data-theme="dark"].sidebar-nav .dropDownCusGrp dd ul b {
    color: var(--text-muted, #94a3b8);
}

/* --------------------------------------------------------------------------
   GLOBAL (not scoped to .q88-refresh) — safe to apply everywhere:
   - Utility classes: only apply when explicitly added to markup
   - Bathymetric watermark: applies to every sidebar-nav page
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   12. Bathymetric Watermark (Figma "App Background" node 250:15309)

   Subtle nautical contour pattern drawn behind every refreshed page. The
   asset is WHITE contour lines on a transparent background, so the light
   theme inverts it to dark lines (visible on the white page chrome) and the
   dark theme keeps it as-is (white lines on the near-black chrome). Opacity
   stays low so the pattern reads as an ornamental watermark, not a texture.

   Scope: body.sidebar-nav only — legacy top-nav layouts and the Blank master
   page are untouched. components.css loads for Q88 (PortalId 0/1) AND Milbros
   (PortalId 2) when Config.EnableRefreshedFrontend is on (Default.Master.cs
   L243), and the same gate sets body.sidebar-nav (L406-408), so rules in this
   file apply to both portals under the refresh flag.

   Rollback: delete this section → pattern disappears site-wide.
   -------------------------------------------------------------------------- */
body.sidebar-nav .q88-content {
    position: relative;
    isolation: isolate;
}

body.sidebar-nav .q88-content::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: url('/images/page/bathymetric-pattern.png');
    background-repeat: repeat-y;
    background-size: 100% auto;
    background-position: top center;
    filter: invert(1);
    opacity: 0.15;
    pointer-events: none;
    z-index: 0;
}

body.sidebar-nav .q88-content > * {
    position: relative;
    z-index: 1;
}

/* DNN paints white-ish backgrounds on these chrome elements which would hide
   the watermark. Force transparent so the pattern shows through. Limited to
   sidebar-nav pages so legacy layouts keep their chrome. */
body.sidebar-nav .ContentPane,
body.sidebar-nav .ContentPaneBody,
body.sidebar-nav .MainTableContent,
body.sidebar-nav #ctl00_cphMiddle,
body.sidebar-nav #cphMiddle_ctl00_divWrap {
    background: transparent !important;
    background-color: transparent !important;
}

/* Dark theme: the source PNG is already white-on-transparent, which is what
   we want on a dark page — drop the invert filter and tune opacity. */
body.sidebar-nav[data-theme="dark"] .q88-content::before {
    filter: none;
    opacity: 0.08;
}

/* Print: no watermark on paper output */
@media print {
    body.sidebar-nav .q88-content::before {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   13. Utility Classes (Phase 4D — inline style replacements)
   -------------------------------------------------------------------------- */
.q88-text-error { color: var(--status-error); }
.q88-text-success { color: var(--status-success-text); }
.q88-text-warning { color: var(--status-warning-text); }
.q88-text-notice { color: var(--status-notice); }
.q88-bg-notice { background-color: var(--surface-notice); }
.q88-bg-highlight { background-color: var(--surface-highlight); }
.q88-border-error { border-color: var(--status-error); }
.q88-text-accent { color: var(--link); }
.q88-text-nav { color: var(--primary-dark); }

/* --------------------------------------------------------------------------
   .q88-card — generic card surface
   Phase B (questionnaire refresh) introduced this; designed for cross-page
   reuse so the selector page (createQuestionnaire.css), questionnaire page,
   and any future "wrap content in a white panel" page can opt in via class.
   Token-driven with literal fallbacks for pages that don't load tokens.css.
   -------------------------------------------------------------------------- */
.q88-card {
    background: var(--card-raised, #ffffff);
    border: 1px solid var(--input, #e2e8f0);
    border-radius: 8px;                                  /* rounded-md */
    padding: 24px 28px;                                   /* Figma 28L/28R, 24T/24B */
    margin: 24px 48px;                                    /* matches selector card */
    box-sizing: border-box;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    color: var(--foreground, #0f172a);
}

/* --------------------------------------------------------------------------
   .q88-card — legacy <table.ContentPane> chain release
   --------------------------------------------------------------------------
   The DNN portal wraps every module in a `<table class="ContentPane">` chain
   that shrink-wraps to its widest child and auto-centers via `margin: 0 auto`.
   When a .q88-card sits inside that chain, the table sizes to the card's
   intrinsic width and centers, defeating the card's fluid `margin: 24px 48px`
   gutters. Release the table on any sidebar-nav page hosting a .q88-card so
   the card actually fills the .q88-content area minus its own gutters.

   Uses :has() — supported in current Chrome/Edge, which is fine here because
   .q88-card only ships under the body.sidebar-nav refresh flag.
   -------------------------------------------------------------------------- */
body.sidebar-nav .q88-content .ContentPane:has(.q88-card),
body.sidebar-nav .q88-content .ContentPaneBody:has(.q88-card),
body.sidebar-nav .ContentPane:has(.q88-card) .MainTableContent > td,
body.sidebar-nav .ContentPane > tbody > tr > td.ContentPaneBody:has(.q88-card) {
    width: 100% !important;
    max-width: none !important;
    margin: 0 !important;
}

/* ==========================================================================
   Edit-pencil icon — global Img-Std-EditV2 swap (refresh, all pages)
   --------------------------------------------------------------------------
   Main.css/MainWhiteout.css paint `.Img-Std-EditV2` with a 15×15 bitmap
   pencil from `/images/icons/StdIcons.png`. Inspections grid (grid.css §7),
   FleetManagement (fleet-management.css §6), Q88 Status (q88status.css §4a)
   and Officer Matrix Vessel (officer-matrix-vessel.css) already replace it
   per-page with a Lucide pencil glyph painted via CSS mask + currentColor.

   This rule applies the same swap globally under the refresh feature flag
   (`body.sidebar-nav`) so every remaining `Img-Std-EditV2` instance — admin
   pages, MooringArrangements, Milbros lists, InspectionContainer,
   ManageEmailPackage, UploadHVPQ, etc. — renders the modern pencil instead
   of the legacy sprite. The per-page rules above are more specific (scoped
   to body.page-X) and continue to win where they exist; this is the
   catch-all for everywhere else.

   Element forms covered:
     • <input type="image">           — asp:ImageButton + clearpixel.gif src
     • <img>                          — direct or rendered inside <a>
     • <a>:empty                      — HyperLink with no Text/children;
                                        sprite paints the anchor itself
     • <a>:has(> ins:only-child)      — LinkButton with empty <ins> spacer
     • <a>:has(> img:only-child)      — asp:HyperLink with ImageUrl set;
                                        renders <a><img src="clearpixel"/></a>;
                                        inner img is hidden below
   Anchors with content (LinkButton wrapping ImageManager etc.) are
   intentionally excluded — masking would hide their children. Those keep
   the legacy sprite until their host page gets a dedicated rule.
   ========================================================================== */
body.sidebar-nav input[type='image'].Img-Std-EditV2,
body.sidebar-nav img.Img-Std-EditV2,
body.sidebar-nav a.Img-Std-EditV2:empty,
body.sidebar-nav a.Img-Std-EditV2:has(> ins:only-child),
body.sidebar-nav a.Img-Std-EditV2:has(> img:only-child),
body.sidebar-nav input[type='image'].Img-Std-Edit,
body.sidebar-nav img.Img-Std-Edit,
body.sidebar-nav a.Img-Std-Edit:empty,
body.sidebar-nav a.Img-Std-Edit:has(> ins:only-child),
body.sidebar-nav a.Img-Std-Edit:has(> img:only-child) {
    width: 24px;
    height: 24px;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: 6px;
    background-image: none !important;
    color: var(--q88-grid-muted-fg, #64748b);
    cursor: pointer;
    vertical-align: middle;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
    -webkit-mask: var(--icon-square-pen) no-repeat center / 16px 16px;
            mask: var(--icon-square-pen) no-repeat center / 16px 16px;
    background-color: currentColor;
}

/* `<asp:LinkButton>` controls (e.g. UDF edit pencil emitted by
   GenerateQuestionnaire.cs:3865 as `<a class="Img-Std Img-Std-EditV2 jqUDF">
   <ins>&nbsp;</ins></a>`) render an empty <ins> spacer so :empty doesn't
   match; the :has(> ins:only-child) branch above catches them, then this
   rule hides the spacer so the mask glyph isn't pushed off-center.
   `<asp:HyperLink ImageUrl="...">` controls (e.g. hlkViewComments in
   TerminalVettingReports.ascx) render `<a><img src="clearpixel.gif"/></a>`;
   hide the inner clearpixel for the same reason. */
body.sidebar-nav a.Img-Std-EditV2 > ins,
body.sidebar-nav a.Img-Std-EditV2 > img,
body.sidebar-nav a.Img-Std-Edit > ins,
body.sidebar-nav a.Img-Std-Edit > img {
    display: none !important;
}

body.sidebar-nav input[type='image'].Img-Std-EditV2:hover,
body.sidebar-nav img.Img-Std-EditV2:hover,
body.sidebar-nav a.Img-Std-EditV2:empty:hover,
body.sidebar-nav a.Img-Std-EditV2:has(> ins:only-child):hover,
body.sidebar-nav a.Img-Std-EditV2:has(> img:only-child):hover,
body.sidebar-nav input[type='image'].Img-Std-Edit:hover,
body.sidebar-nav img.Img-Std-Edit:hover,
body.sidebar-nav a.Img-Std-Edit:empty:hover,
body.sidebar-nav a.Img-Std-Edit:has(> ins:only-child):hover,
body.sidebar-nav a.Img-Std-Edit:has(> img:only-child):hover {
    color: var(--q88-grid-primary, #0d9488);
    border-color: var(--q88-grid-primary, #0d9488);
}

/* Disabled / read-only variants — same Lucide pencil glyph, dimmer, no
   pointer affordance. Covers `Img-Std-EditV2Disabled` (Milbros heavy
   user: LibraryNoteList, DocumentNoteList, CommodityContainerPriorCargo,
   CommodityContainerCoating) plus the older `Img-Std-EditDisabled`
   token (CertificateDocumentList, FleetReportList). Without this rule
   these still painted the 15×15 grayscale bitmap from StdIcons.png. */
body.sidebar-nav input[type='image'].Img-Std-EditV2Disabled,
body.sidebar-nav img.Img-Std-EditV2Disabled,
body.sidebar-nav a.Img-Std-EditV2Disabled:empty,
body.sidebar-nav a.Img-Std-EditV2Disabled:has(> ins:only-child),
body.sidebar-nav input[type='image'].Img-Std-EditDisabled,
body.sidebar-nav img.Img-Std-EditDisabled,
body.sidebar-nav a.Img-Std-EditDisabled:empty,
body.sidebar-nav a.Img-Std-EditDisabled:has(> ins:only-child) {
    width: 24px;
    height: 24px;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: 6px;
    background-image: none !important;
    color: var(--q88-grid-muted-fg, #64748b);
    cursor: default;
    vertical-align: middle;
    opacity: 0.45;
    -webkit-mask: var(--icon-square-pen) no-repeat center / 16px 16px;
            mask: var(--icon-square-pen) no-repeat center / 16px 16px;
    background-color: currentColor;
}

body.sidebar-nav a.Img-Std-EditV2Disabled > ins,
body.sidebar-nav a.Img-Std-EditDisabled > ins {
    display: none !important;
}

/* ==========================================================================
   Edit-pencil icon — global src-based swap (refresh, all pages)
   --------------------------------------------------------------------------
   Catch-all for legacy edit icons emitted WITHOUT the `Img-Std-EditV2`
   class. ~30 ASCX/ASPX files plus codebehind sites still build
   `<asp:Image/ImageButton/HyperLink ImageUrl="~/images/edit.gif">`, raw
   `<img src="/images/icons/edit.png">`, etc. The V2 class rule above only
   matches markup that opted in via `CssClass`; this rule matches the
   legacy `src` URL directly so admin (Tabs, TabLayout, CompanyLicense),
   DesktopModules (Announcements, Contacts, Document, Events, QuickLinks,
   Links), Jotun (PRLSearch, EditPRLNotes), TerminalVetting reports,
   MessageReport, UserManagement, Approvals, ImageManager, ForumList,
   VariableGridQuestion and codebehind-built tank-plan / generated-
   questionnaire / question-settings pencils all render the modern
   Lucide pencil without per-control markup churn.

   Per-page rules with id/class selectors (e.g. questionnaire.css
   `body.page-questionnaire #tblQuestionnaire img[src$="…edit.png"]`)
   remain more specific and continue to win where they exist.

   Composite branded icons (`notes-Edit.gif`, `TVR-Edit.gif`) are
   intentionally excluded — they're not the bare-pencil glyph.
   ========================================================================== */
body.sidebar-nav img[src*='/edit.gif'],
body.sidebar-nav img[src*='/images/icons/edit.png'],
body.sidebar-nav img[src*='/images/icons/editDisabled.png'],
body.sidebar-nav input[type='image'][src*='/edit.gif'],
body.sidebar-nav input[type='image'][src*='/images/icons/edit.png'] {
    width: 24px;
    height: 24px;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid transparent;
    border-radius: 6px;
    background-image: none !important;
    color: var(--q88-grid-muted-fg, #64748b);
    cursor: pointer;
    vertical-align: middle;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
    -webkit-mask: var(--icon-square-pen) no-repeat center / 16px 16px;
            mask: var(--icon-square-pen) no-repeat center / 16px 16px;
    background-color: currentColor;
}

/* Disabled state — same glyph, dimmer, no pointer affordance. */
body.sidebar-nav img[src*='/images/icons/editDisabled.png'] {
    opacity: 0.45;
    cursor: default;
}

body.sidebar-nav img[src*='/edit.gif']:hover,
body.sidebar-nav img[src*='/images/icons/edit.png']:hover,
body.sidebar-nav input[type='image'][src*='/edit.gif']:hover,
body.sidebar-nav input[type='image'][src*='/images/icons/edit.png']:hover {
    color: var(--q88-grid-primary, #0d9488);
    border-color: var(--q88-grid-primary, #0d9488);
}

/* ==========================================================================
   Calendar trigger icon — global src-based swap (refresh, all pages)
   --------------------------------------------------------------------------
   The shared date-picker trigger emitted by Controls/Calendar.ascx and
   DesktopModules/CalendarControl.ascx renders as
       <input type="image" class="jaQCal" src="/images/cal.gif">
   (or `/images/icons/calendar.gif` / `…/calendarDisabled.gif` set in
   codebehind). A handful of pages also emit raw
       <img src="/images/icons/_24px_Height/calendar.gif">
   inline (e.g. SubscriptionCompare.ascx).

   This rule paints all four src variants with the Lucide calendar glyph
   used elsewhere in the refresh (certificates.css §calendar pseudo).
   Click target stays intact — we mask the element itself, we don't hide
   it. Per-page rules (certificates.css, EditProfile.css, datePicker.css,
   editQuestionAnswerPopup.css) are more specific and continue to win.
   ========================================================================== */
body.sidebar-nav img[src*='/cal.gif'],
body.sidebar-nav img[src*='/images/icons/calendar.gif'],
body.sidebar-nav img[src*='/images/icons/calendarDisabled.gif'],
body.sidebar-nav img[src*='/images/icons/_24px_Height/calendar.gif'],
body.sidebar-nav input[type='image'][src*='/cal.gif'],
body.sidebar-nav input[type='image'][src*='/images/icons/calendar.gif'],
body.sidebar-nav input[type='image'][src*='/images/icons/calendarDisabled.gif'] {
    /* !important on width/height/border-width because the shared
       Controls/Calendar.ascx ImageButton renders an inline
       `style="height:19px;width:20px;border-width:0px;"` from its
       Width/Height ASP properties — without !important the legacy 20×19
       wins and the Lucide mask renders smaller than the 24×24 design intent. */
    width: 24px !important;
    height: 24px !important;
    padding: 4px;
    box-sizing: border-box;
    border: 1px solid transparent !important;
    border-radius: 6px;
    background-image: none !important;
    color: var(--q88-grid-muted-fg, #64748b);
    cursor: pointer;
    vertical-align: middle;
    transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
    -webkit-mask: var(--icon-calendar) no-repeat center / 16px 16px;
            mask: var(--icon-calendar) no-repeat center / 16px 16px;
    background-color: currentColor;
}

/* Disabled state — same glyph, dimmer, no pointer affordance. */
body.sidebar-nav img[src*='/images/icons/calendarDisabled.gif'],
body.sidebar-nav input[type='image'][src*='/images/icons/calendarDisabled.gif'] {
    opacity: 0.45;
    cursor: default;
}

body.sidebar-nav img[src*='/cal.gif']:hover,
body.sidebar-nav img[src*='/images/icons/calendar.gif']:hover,
body.sidebar-nav input[type='image'][src*='/cal.gif']:hover,
body.sidebar-nav input[type='image'][src*='/images/icons/calendar.gif']:hover {
    color: var(--q88-grid-primary, #0d9488);
    border-color: var(--q88-grid-primary, #0d9488);
}

/* ==========================================================================
   Favorite-star icon — global Lucide swap (refresh, all pages)
   --------------------------------------------------------------------------
   Main.css L1355-1357 / MainWhiteout.css L2500-2519 paint `.Img-StarOn` and
   `.Img-StarOff` as a 9×9 raster from `/images/markers/(no_)?star.png`.
   Page-specific re-skins (from-to-cleaning §9 = 14×14, MilbrosCommodityRefresh
   = 16×16, milbros-search §7b = 18×18) upscaled the 9px PNG via `background-
   size: contain` — fuzzy at any size > 9 and inconsistent across pages.

   Canonical Figma reference: Milbros file ISZ58jrGcp1LwMEJeeG00Q, "star 1"
   variants frame 2064:10012:
     - Property 1=Regular        (2064:10011)  24×24, stroke base/border #e2e8f0 — OFF
     - Property 1=Regular-light  (2064:10013)  24×24, fill   base/ring   #64748b — ON
     - Property 1=sm             (2064:10015)  16×16, stroke base/border #e2e8f0 — OFF small
     - Property 1=sm-light       (2064:10017)  16×16, fill   base/ring   #64748b — ON small

   All current Q88/Milbros favorite-star renders sit inside 14px-text grids
   or spec rows — the SMALL (16×16) variant is the correct size everywhere.
   Color matches Figma `base/ring` #64748b (slate-500) for the filled/On
   state. Outline uses slate-400 #94a3b8 instead of Figma's base/border
   slate-200 — the slate-200 stroke is too pale to register against the
   row hover bg on dense grids, so we step one stop darker for legibility.

   Targets the `Img-StarOff`/`Img-StarOn` CLASS so both JS-template renders
   (Pointer companion class, ~10 ASCX/codebehind sites) AND
   Q88WSInternal.cs:1307 (Pointer absent) get the swap. The registered-vessel
   marker stars (`<asp:Image ImageUrl="~/images/markers/star.png">` in
   Q88Status.ascx / VesselManagement.ascx / UsersWithSimilarIP.ascx.cs) emit
   a bare `<img src=...>` with no Img-Star* class and an inline `width="9"`
   HTML attr — matched by `img[src$="/markers/star.png"]` / `_no_star.png`
   so they render the same 16×16 Lucide visual but stay NON-CLICKABLE
   (cursor:default, no hover swap). Uses CSS `content:` URL to replace the
   loaded raster — `.Img-Star*` uses `clearpixel.gif` src so it can rely on
   background-image, but the marker IMGs load the real PNG and would paint
   over a background.

   Per-page rules in from-to-cleaning.css §9, milbros-search.css §7b and
   MilbrosCommodityRefresh.css star block are removed since they conflict
   with the canonical size. Longhand `background-color` (not shorthand
   `background:`) per css-shorthand-var-important-parser-trap.
   ========================================================================== */
body.sidebar-nav img.Img-StarOff,
body.sidebar-nav img.Img-StarOn,
body.sidebar-nav img.FavoriteOff,
body.sidebar-nav img.FavoriteOn {
    width: 16px !important;
    height: 16px !important;
    margin: 0 !important;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>") !important;
    background-repeat: no-repeat !important;
    background-position: center !important;
    background-size: 16px 16px !important;
    background-color: transparent !important;
    vertical-align: middle !important;
    cursor: pointer;
}
/* `FavoriteOn`/`FavoriteOff` are the legacy favourite-star classes emitted by
   Milbros SearchAdditives.ascx ("Search Favorites" radio option) — same
   clearpixel.gif src as Img-Star*, so they take the same filled/outline swap
   (replaces the legacy yellow StdIcons sprite star with the slate Lucide star). */
body.sidebar-nav img.Img-StarOn,
body.sidebar-nav img.FavoriteOn {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='%2364748b' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>") !important;
}
body.sidebar-nav img.Img-StarOff:hover,
body.sidebar-nav img.FavoriteOff:hover {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>") !important;
}

body.sidebar-nav img[src$="/markers/star.png"],
body.sidebar-nav img[src$="/markers/no_star.png"] {
    width: 16px !important;
    height: 16px !important;
    vertical-align: middle !important;
    cursor: default !important;
}
body.sidebar-nav img[src$="/markers/star.png"] {
    content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='%2364748b' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>");
}
body.sidebar-nav img[src$="/markers/no_star.png"] {
    content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>");
}

/* ==========================================================================
   AlertBox popup — MOVED to styles/alert-box.css (QEN-8865).

   The rules used to live here, but components.css is registered only by
   Default.master.cs. Blank.master.cs (every LoadControl.aspx / window.open
   popup) never loads it, so an alert raised inside a popup window kept
   rendering the legacy navy title band + yellow body — e.g. the Officer
   Matrix "Compliance Status" window (body.popup-omcompliance) after saving
   its Compliance Settings. Split into a shared stylesheet loaded by BOTH
   masters, same pattern as loading-modal.css and icon-swaps.css.
   ========================================================================== */

/* ==========================================================================
   Validation hint popover (`.hint`) — Q88Search.ascx surfaces client-side
   ValidationGroup errors inline next to the offending field via:
       <span class="hint" id="hintN" onclick="HideHint(...)">
         <div id="valDisplayN"></div>        ← error text injected by JS
         <span class="hint-pointer"></span>   ← GIF down-arrow (legacy)
         <span style="position:absolute;bottom:0;right:0">
           <a href="javascript:HideHint(...)">[x] Close</a>
         </span>
       </span>
   ShowHint()/HideHint() in Scripts/script.js toggle .style.display.

   Legacy chrome (MainWhiteout.css §1219): `--status-warning` yellow body
   + `--brand-dark` 1px border + HintPointerBottom.gif arrow. Refresh
   aligns with the §9.10 Alert Dialog and the AlertBox refresh above —
   white card, slate-200 border, 8px radius, shadow/sm. Amber Lucide
   AlertTriangle glyph carries the warning semantic without the yellow
   body. The "[x] Close" text link is replaced by a Lucide X icon (entire
   `.hint` already carries `onclick="HideHint(...)"` so the X is just a
   visual affordance, not the only close target). The GIF arrows become
   CSS triangles whose fill matches the white card body.

   `box-sizing: border-box` is scoped to `.hint` only (per MEMORY: do
   NOT set globally) so the legacy inline `width:350px`/`width:300px`
   stays as the TOTAL width — without this the new horizontal padding
   would push the popup off-screen on a 350px-positioned trigger.

   Legacy `.hint-pointer { top: 48px }` was calibrated to the 38px-tall
   legacy card; with our new height: auto we re-anchor the down-pointer
   to the actual bottom edge via `top: auto; bottom: -7px`.
   ========================================================================== */
body.sidebar-nav .hint {
    box-sizing: border-box;
    background-color: var(--surface-card, #ffffff) !important;
    border: 1px solid var(--border-subtle, #e2e8f0);
    border-radius: 8px;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.10),
                0 2px 4px -2px rgba(0, 0, 0, 0.10);
    color: var(--text-primary, #1e293b);
    font-size: 13px;
    line-height: 18px;
    font-weight: 400;
    height: auto;
    min-height: 44px;
    padding: 10px 32px 10px 32px;
    /* text-align is inherited; some triggers (e.g. Q88Search's "Search" cell
       uses align="right") would otherwise right-align the warning copy. Pin it
       left so the validation message reads left-to-right beside the icon. */
    text-align: left;
    /* never inherit a nowrap container — the message must wrap */
    white-space: normal;
}

/* Amber AlertTriangle glyph at top-left — carries the warning semantic
   that the yellow body used to (in lieu of the now-gone status-warning
   background fill). 16x16 inside an 8px inset. */
body.sidebar-nav .hint::before {
    content: "";
    position: absolute;
    left: 8px;
    top: 10px;
    width: 16px;
    height: 16px;
    background-color: #d97706;
    -webkit-mask: var(--icon-triangle-alert) center / 16px 16px no-repeat;
            mask: var(--icon-triangle-alert) center / 16px 16px no-repeat;
}

/* Shift `.hint` content right so it clears the AlertTriangle without
   needing extra wrapping markup — `text-indent` on a block doesn't
   apply to subsequent wrapped lines, but the inner `valDisplay` div
   sits to the right of the icon naturally given our padding. */
body.sidebar-nav .hint > div[id^="valDisplay"] {
    padding-left: 0;
    margin-left: 0;
}

/* Close-wrapper span — strip the inline `position:absolute;bottom:0;
   right:0` and re-anchor to top-right of the card. Specificity 0,0,3,3
   plus `!important` is required to beat the inline style. Limited to
   the span that actually contains the HideHint anchor (the .hint also
   has another inner span — `.hint-pointer` — which we don't want to
   touch here). */
body.sidebar-nav .hint > span:has(> a[href*="HideHint"]) {
    position: absolute !important;
    top: 6px !important;
    right: 6px !important;
    bottom: auto !important;
    left: auto !important;
    width: 20px;
    height: 20px;
}

/* Close anchor — replace "[x] Close" text with a Lucide X glyph
   (16x16 within a 20x20 click target). `text-indent: -9999px` +
   `overflow: hidden` + `font-size: 0` push the legacy text out of
   the frame without removing it from the DOM (keeps a11y semantics
   for screen readers via the existing `[x] Close` text content). */
body.sidebar-nav .hint a[href*="HideHint"] {
    display: block;
    width: 20px;
    height: 20px;
    overflow: hidden;
    text-indent: -9999px;
    white-space: nowrap;
    font-size: 0 !important;
    background-color: transparent;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M18 6 6 18'/><path d='m6 6 12 12'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
    text-decoration: none !important;
    cursor: pointer;
    border-radius: 4px;
}

body.sidebar-nav .hint a[href*="HideHint"]:hover {
    background-color: #f1f5f9;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f172a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M18 6 6 18'/><path d='m6 6 12 12'/></svg>");
}

/* Pointer arrows — replace the legacy GIFs (HintPointerBottom.gif /
   HintPointerTop.gif) with CSS triangles whose fill matches the white
   card body. `background: none` first clears the legacy GIF, then
   `background-color` fills the triangle (clip-path masks the
   non-triangle area). Width/height bumped from 19x10 to 14x8 — the
   legacy GIF triangle had a built-in drop-shadow that we don't need
   on a white card. */
body.sidebar-nav .hint .hint-pointer,
body.sidebar-nav .hint .hint-pointerTop {
    background: none !important;
    background-color: var(--surface-card, #ffffff) !important;
    width: 14px;
    height: 8px;
    z-index: 99;
}

body.sidebar-nav .hint .hint-pointer {
    top: auto !important;
    bottom: -7px;
    clip-path: polygon(0 0, 100% 0, 50% 100%);
}

body.sidebar-nav .hint .hint-pointerTop {
    top: -7px;
    clip-path: polygon(0 100%, 100% 100%, 50% 0);
}

/* ==========================================================================
   Shared Modal.ascx chrome — refresh re-skin (DESIGN.md §9.10 + §15.13.11)
   --------------------------------------------------------------------------
   Re-skin EVERY <uc:Modal> instance rendered on a refreshed page (anything
   carrying body.sidebar-nav) into a flat white card: 1px slate-200 border,
   12px radius, soft shadow, 24/28 padding, Inter typography, Lucide X close
   button. Mirrors the certificates.css "New Certificate/Document modal"
   exemplar but kept generic (no form-row tweaks — those stay in per-page
   files like certificates.css when needed).

   Covers all <uc:Modal> instances on refreshed pages:
     - Inspections (5 modals, incl. mpeNewInspection "Inspection: New")
     - VettingAnalytics (mpeRptQDetails, mpeFleetRiskDetails)
     - FleetReportList (mpeScheduledReports)
     - Milbros booking/voyage/commodity (when those pages get sidebar-nav)
     - Anything else mounting <uc:Modal> under body.sidebar-nav

   Per-page files (certificates.css, etc.) can still scope tighter rules
   to a SPECIFIC pnlModalPopup id for form-row tweaks — those win on
   specificity.

   ModalPopupExtender-only popups (Email.ascx pnlAttachment / pnlAddressBook,
   VesselManagement.ascx mpeModInput / mpeUDF / mpeDeleteRequest) do NOT use
   Modal.ascx and won't be touched by this block — they need per-page rules.
   ========================================================================== */

/* Outer panel — `.modPopPnl` carries inline `style="display:none; width:<ascx>px"`
   set by Modal.ascx codebehind. Preserve the ascx width; restyle chrome. */
body.sidebar-nav .modPopPnl {
    background: var(--surface-raised, #ffffff);
    border: 1px solid var(--raw-slate-200, var(--border-default, #e2e8f0));
    border-radius: 12px;
    box-shadow:
        0 4px 6px -1px rgba(0, 0, 0, 0.10),
        0 2px 4px -1px rgba(0, 0, 0, 0.06);
    padding: 24px;
    box-sizing: border-box;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    color: var(--text-primary, #0f172a);
    max-width: calc(100vw - 32px);
}

/* Hide the legacy 3-column corner-icon decorations (MilbrosModal.png sprites
   + the dotted "modPopContentTop" pixel-bleed row). */
body.sidebar-nav .modPopPnl .modPopContentTop,
body.sidebar-nav .modPopPnl .leftCornerIcon,
body.sidebar-nav .modPopPnl .rightCornerIcon {
    display: none !important;
}

/* Flatten the legacy 3-column `<table class="modPopupTbl">` chain so the
   header/body/footer stack as block-flow inside the card. */
body.sidebar-nav .modPopPnl > .modPopupTbl,
body.sidebar-nav .modPopPnl > .modPopupTbl > tbody,
body.sidebar-nav .modPopPnl > .modPopupTbl > tbody > tr,
body.sidebar-nav .modPopPnl > .modPopupTbl > tbody > tr > td {
    display: block;
    width: auto !important;
    height: auto;
    padding: 0;
    margin: 0;
    border: 0 !important;
    background: transparent;
    vertical-align: baseline;
}

/* Header bar (`.hdrTblBar`) — was navy ribbon `var(--brand-accent)` legacy
   teal/cyan. Strip background, flatten inner title-table to a flex row
   that pins title left + close X right. Below-padding 16px gives space
   to the body. */
body.sidebar-nav .modPopPnl .hdrTblBar {
    background: transparent !important;
    /* Vertical padding only (16px above the title, 16px below before the body).
       NO horizontal padding: the card's 24px gutter (.modPopPnl padding) is the
       single content edge, so the title + close X line up on the SAME vertical
       as the body fields and footer buttons. (QEN-8801: was `16px 16px 16px
       16px`, which inset the header to 44px vs the body/footer at 28px — the
       title stuck in and the X stuck in, misaligned with everything below.) */
    padding: 16px 0 16px 0 !important;
    height: auto !important;
}

/* Anchor Edit Observation modal popup to VIEWPORT so the popup never
   overflows the bottom of the screen. The legacy inline style positions
   it as `position: absolute; top: 2%` — but the offsetParent is a tall
   scrolled container, so `top: 2%` renders at y≈99px instead of the
   intended ~20px, pushing the 950h popup 49px below viewport bottom on
   a 1000h viewport (footer scrolls off-screen).

   Inline style also sets `display: flex; align-items: center` which causes
   the modPopupTbl (978h with header+body+footer) to be vertically centered
   inside the popup — when content > popup height, it overflows BOTH top
   and bottom equally, pushing the header chrome above the popup top edge.
   Override align-items to flex-start so content starts from top.

   Fix:
   1. position: fixed so top resolves against viewport (not offsetParent)
   2. max-height: 100vh - 32px so popup never overflows bottom
   3. align-items: flex-start so chrome stays at top when content overflows
   4. overflow-y: auto so excess content scrolls inside the popup */
body.sidebar-nav [id$="_mod_mpeEditObservation_pnlModalPopup"] {
    position: fixed !important;
    top: 16px !important;
    left: 50% !important;
    transform: translateX(-50%) !important;
    max-height: calc(100vh - 32px) !important;
    margin: 0 !important;
    overflow-y: auto !important;
    align-items: flex-start !important;  /* override inline align-items:center */
    justify-content: flex-start !important;
}
body.sidebar-nav .modPopPnl .hdrTblBar > table {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    width: 100% !important;
    border-collapse: collapse;
}
body.sidebar-nav .modPopPnl .hdrTblBar > table > tbody,
body.sidebar-nav .modPopPnl .hdrTblBar > table > tbody > tr {
    display: contents;
}
body.sidebar-nav .modPopPnl .hdrTblBar > table td {
    display: block;
    padding: 0 !important;
    width: auto !important;
}
body.sidebar-nav .modPopPnl .hdrTblBar > table td:first-child {
    flex: 1 1 auto;
    padding-left: 0 !important;
}

/* Title cluster: `Title` + `lblPopupTitleSub` ("`: Sub`" — colon is in the
   subtitle text, prepended by Modal.ascx.cs). Title bold, subtitle muted-
   regular for a clean ChicagoStandard look — matches Figma §9.10 chrome. */
body.sidebar-nav .modPopPnl .modPopTitlePnl {
    font-size: 18px;
    line-height: 28px;
    font-weight: 600;
    color: var(--text-primary, #0f172a);
    padding: 0 !important;
}
/* `lblPopupTitle` is the inner `<span>` rendering "Edit Observation" — its
   12px-bold legacy size from MainWhiteout wins over the parent panel rule
   unless we override the span itself. */
body.sidebar-nav .modPopPnl .modPopTitlePnl > span,
body.sidebar-nav .modPopPnl [id$="_lblPopupTitle"] {
    font-size: 18px !important;
    line-height: 28px !important;
    font-weight: 600 !important;
    color: var(--text-primary, #0f172a) !important;
}
body.sidebar-nav .modPopPnl .modPopTitlePnl .popupTitleSub,
body.sidebar-nav .modPopPnl [id$="_lblPopupTitleSub"] {
    font-size: 18px !important;
    line-height: 28px !important;
    font-weight: 400 !important;
    color: var(--text-primary, #0f172a) !important;
}

/* Close X — hide legacy `close_red.gif` red square, paint a Lucide X via
   currentColor + mask. 16px hit area with subtle hover muting. */
body.sidebar-nav .modPopPnl [id$="_lnkClose"] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    color: var(--text-primary, #0f172a);
    cursor: pointer;
    text-decoration: none;
    background: transparent;
    border-radius: 4px;
}
body.sidebar-nav .modPopPnl [id$="_lnkClose"] img {
    display: none !important;
}
body.sidebar-nav .modPopPnl [id$="_lnkClose"]::before {
    content: "";
    display: block;
    width: 16px;
    height: 16px;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'/><line x1='6' y1='6' x2='18' y2='18'/></svg>") no-repeat center / 16px;
            mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'/><line x1='6' y1='6' x2='18' y2='18'/></svg>") no-repeat center / 16px;
}
body.sidebar-nav .modPopPnl [id$="_lnkClose"]:hover {
    color: var(--text-muted, #475569);
    background: var(--surface-hover, #f1f5f9);
}

/* Body region (`.mainBG` carried `--surface-page` grey in legacy → transparent
   so the card's white bg shows). `.modPopContent` zeroes its 6/10/10/10 legacy
   padding — the outer panel padding (24/28) already provides the gutter. */
body.sidebar-nav .modPopPnl .mainBG {
    background: transparent !important;
}
body.sidebar-nav .modPopPnl .modPopContent {
    padding: 0 !important;
    color: var(--text-primary, #0f172a);
    font-size: 14px;
    line-height: 20px;
}

/* Footer (`.modPopFooter`) — legacy `padding: 15px; text-align: right`.
   New: flex-end cluster with 12px gap, 16px top padding for separation
   from the body. Buttons themselves keep whatever per-page styling exists
   (LinkButton rules are scoped elsewhere in components.css). */
body.sidebar-nav .modPopPnl .modPopFooter {
    padding: 16px 0 0 0 !important;
    text-align: right;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 12px;
}
body.sidebar-nav .modPopPnl .modPopFooter:empty {
    display: none;
}

/* Footer buttons — legacy `<asp:LinkButton>` renders as `<a class="LinkButton">`
   with an `<ins>&nbsp;</ins>` spacer (MEMORY `linkbutton-ins-spacer-trap`).
   Restyle to DESIGN.md §9.10:
     - Primary `.LinkButton` → teal pill, 36h, 8px radius, white text
     - Secondary `.LinkButton.Secondary` → ghost slate pill, 36h, 8px radius
   The `<ins>` spacer is killed (would be a flex item and offset the label). */
/* QEN-8801: !important dropped here. This block's specificity is (0,4,2); on
   refresh it only needs to beat the base button block above (0,2,2 for the
   `a.LinkButton` selector) and the NORMAL `a:link` (0,1,1) — MainWhiteout's
   `.LinkButton` !important is gated
   `body:not(.sidebar-nav)` by Target B (commit 132bbd42), so nothing with
   !important competes on refresh. Page-level popup-footer overrides that need
   a different look (historyPopup Close, etc.) now tie at (0,4,2) and win by
   source order without needing !important themselves. */
body.sidebar-nav .modPopPnl .modPopFooter a.LinkButton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box; /* else legacy 6px y-padding + 1px border stack on the 36px → ~50px buttons */
    height: 36px;
    padding: 0 16px;
    border-radius: 8px;
    background: var(--button-primary-bg, var(--brand-primary, #0d9488));
    color: var(--button-primary-text, #ffffff);
    border: 1px solid var(--button-primary-bg, var(--brand-primary, #0d9488));
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 120ms ease, border-color 120ms ease;
    min-width: 64px;
    box-shadow: none;
}
body.sidebar-nav .modPopPnl .modPopFooter a.LinkButton:hover {
    background: var(--button-primary-bg-hover, var(--brand-primary-hover, #0f766e));
    border-color: var(--button-primary-bg-hover, var(--brand-primary-hover, #0f766e));
    color: var(--button-primary-text, #ffffff);
    text-decoration: none;
}
body.sidebar-nav .modPopPnl .modPopFooter a.LinkButton.Secondary {
    background: var(--surface-raised, #ffffff);
    color: var(--text-primary, #0f172a);
    border: 1px solid var(--raw-slate-200, var(--border-default, #e2e8f0));
}
body.sidebar-nav .modPopPnl .modPopFooter a.LinkButton.Secondary:hover {
    background: var(--surface-hover, #f1f5f9);
    border-color: var(--raw-slate-200, var(--border-default, #e2e8f0));
    color: var(--text-primary, #0f172a);
}
body.sidebar-nav .modPopPnl .modPopFooter a.LinkButton > ins {
    display: none;
}

/* ==========================================================================
   Legacy subModal popup chrome (DESIGN.md §9.10)
   --------------------------------------------------------------------------
   `Custom.Utilities.JavascriptHelper.Modal` (SharedAssemblies/Custom.Web)
   ships a DHTML popup built by Scripts/Modal/subModal.js into the parent
   page DOM. The IDs are fixed globally (#popupMask / #popupContainer /
   #popupInner / #popupTitleBar / #popupTitle / #popupControls / #popupFrame).
   Legacy chrome is a navy #78ABDE title bar with 2px black border on
   #popupInner.

   Re-skin to match §9.10: rgba/blur backdrop, white card with 1px slate-200
   border + 12px radius + soft shadow, Inter SemiBold 16/24 title, Lucide X
   close. Used by Terminal Vetting Reports (VettingComments.aspx popup),
   HVPQ Quality Check, Terminal Email and other consumers of MakeModal.
   ========================================================================== */

body.sidebar-nav #popupMask {
    background: rgba(0, 0, 0, 0.4) !important;
    background-image: none !important;
    opacity: 1 !important;
    filter: none !important;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}

body.sidebar-nav #popupContainer {
    background: transparent !important;
    padding: 0 !important;
}

body.sidebar-nav #popupInner {
    background-color: var(--surface-raised, #ffffff) !important;
    border: 1px solid var(--raw-slate-200, var(--border-default, #e2e8f0)) !important;
    border-radius: 12px !important;
    box-shadow:
        0 4px 6px -1px rgba(0, 0, 0, 0.10),
        0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
    overflow: hidden;
    height: 100%;
    box-sizing: border-box;
}

body.sidebar-nav #popupTitleBar {
    background-color: var(--surface-raised, #ffffff) !important;
    background-image: none !important;
    border: 0 !important;
    color: var(--text-primary, #0f172a) !important;
    height: auto !important;
    min-height: 48px;
    padding: 12px 16px !important;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    box-sizing: border-box;
    text-shadow: none;
    font-weight: 600;
}

body.sidebar-nav #popupTitle {
    float: none !important;
    flex: 1 1 auto;
    min-width: 0;
    color: var(--text-primary, #0f172a) !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 16px !important;
    font-weight: 600 !important;
    line-height: 24px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Close affordance — the legacy close.gif <img> stays clickable (preserves
   onclick="hidePopWin(false)") but is rendered invisibly on top of a
   ::before-painted Lucide X mask so the click target is unchanged. */
body.sidebar-nav #popupControls {
    float: none !important;
    flex: 0 0 auto;
    position: relative;
    width: 24px;
    height: 24px;
    border-radius: 4px;
    color: var(--text-muted, #475569);
    cursor: pointer;
}
body.sidebar-nav #popupControls:hover {
    background: var(--raw-slate-100, var(--surface-muted, #f1f5f9));
    color: var(--text-primary, #0f172a);
}
body.sidebar-nav #popupControls::before {
    content: "";
    position: absolute;
    inset: 3px;
    background-color: currentColor;
    pointer-events: none;
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'/><line x1='6' y1='6' x2='18' y2='18'/></svg>") no-repeat center / 18px;
            mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='18' y1='6' x2='6' y2='18'/><line x1='6' y1='6' x2='18' y2='18'/></svg>") no-repeat center / 18px;
}
body.sidebar-nav #popupControls img {
    width: 24px !important;
    height: 24px !important;
    opacity: 0;
    cursor: pointer;
    display: block;
    border: 0 !important;
}

body.sidebar-nav #popupFrame {
    background-color: var(--surface-raised, #ffffff);
    border: 0 !important;
}

/* ==========================================================================
   §9.11 — Shared CustomFilter MPE confirm dialogs (DESIGN.md §9.10 chrome)
   --------------------------------------------------------------------------
   DesktopModules/CustomFilter.ascx (the "Custom View" editor, reached from the
   GridViewSelector toolbar on every refreshed grid page) hosts THREE legacy
   <uc:ModuleTemplate> confirm dialogs, each wrapped in an
   ajaxToolkit:ModalPopupExtender:

     #pnlCancelIncompletePendingChanges (modCancelIncompletePendingChanges)
     #pnlCancelConfirm                  (modFormChanged)
     #pnlDeleteConfirm                  (modDeleteConfirm)

   These do NOT use Modal.ascx, so the §9.10 `.modPopPnl` chrome above never
   reaches them — they render legacy navy (#2D3663 title ribbon, #003366
   border, #ddd footer band). This block replicates the §9.10 dialog chrome
   mapped onto the ModuleTemplate class names (.modContainerStd /
   .modInnerContainer / .modTitle (.modTLeft/.modTRight) / .modMain /
   .modFooter2), cloning scheduledreports.css §8.1–§8.8.

   SCOPED to the three panel IDs via [id$='...'] (the panels render with
   ASP.NET naming-container prefixes — e.g.
   ctl00_cphMiddle_ctl00_modCustomFilter_pnlDeleteConfirm — so a bare
   #pnlDeleteConfirm would never match). ID scoping is mandatory here: the page
   carries SEVEN .modContainerStd elements (the main editor card, the two
   ScheduleDetailModal popups, the GridColorsCriteria popup, plus these three),
   and a bare .modContainerStd rule would clobber the un-ready ones.

   Hardcoded hex (not var()) on border/background/button colours: these fight
   legacy MainWhiteout `!important` shorthands, and per DESIGN.md §32.2–§32.3 a
   var() inside a shorthand+!important either drops the next declaration or
   loses the cascade. Values mirror the §9.10 resolved tokens (slate-200
   #e2e8f0, text #0f172a, label #475569, teal #0d9488 / #0f766e, destructive
   #dc2626 / #b91c1c). Background/border use LONGHAND, never shorthand, to dodge
   the shorthand+var()+!important parser drop.

   Close X: each dialog's .modTRight anchor already carries a working onclick
   (ShowModal('mpeXxx', false); return false;) but emits no <img> glyph (Q88
   ImageManager → text-only on PortalId 0/1/2). Paint a Lucide X via ::before
   mask — no markup change needed.
   ========================================================================== */

/* §9.11.1 — Release the transparent table/cell wrappers; the painted card is
   .modInnerContainer. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd,
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd > tbody > tr > td,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd > tbody > tr > td,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd > tbody > tr > td {
    width: auto !important;
    background-color: transparent !important;
    border: 0 !important;
    padding: 0 !important;
}

/* §9.11.2 — Outer card: white surface, slate-200 border, 12px radius, soft
   shadow, Inter. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modInnerContainer,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modInnerContainer,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modInnerContainer {
    box-sizing: border-box;
    min-width: 320px;
    background-color: #ffffff !important;
    border: 1px solid #e2e8f0 !important;
    border-radius: 12px !important;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.10), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
    overflow: hidden;
    padding: 0 !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    color: #0f172a;
}

/* The three sections are legacy content-box at width:100% — their 16px side
   padding then overflows the card by 32px and overflow:hidden clips the
   right-seated close X. Force border-box so padding stays inside the card. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTitle,
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modMain,
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTitle,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modMain,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTitle,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modMain,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 {
    box-sizing: border-box !important;
    width: 100% !important;
}

/* Collapse the empty ModuleTemplate header/sub panels between title and body. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTitleHeader:empty,
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modSub1:empty,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTitleHeader:empty,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modSub1:empty,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTitleHeader:empty,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modSub1:empty {
    display: none !important;
}

/* §9.11.3 — Header: strip the navy ribbon, flex row (title left, close X
   right), 16/16/12 padding cadence. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTitle,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTitle,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTitle {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    background-color: transparent !important;
    border: 0 !important;
    padding: 16px 16px 12px 16px !important;
    height: auto !important;
}

/* §9.11.4 — Title text. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTLeft,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTLeft,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTLeft {
    flex: 1 1 auto;
    min-width: 0;
    background-color: transparent !important;
    color: #0f172a !important;
    font-size: 18px !important;
    line-height: 28px !important;
    font-weight: 600 !important;
    padding: 0 !important;
    text-align: left;
}

/* §9.11.5 — Close X: paint a Lucide X via currentColor mask on the (otherwise
   empty) TitleRight anchor; ImageManager emits no glyph on Q88 portals, and the
   anchor's onclick (ShowModal('mpeXxx', false)) is already wired in markup, so
   no markup change is needed. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTRight,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTRight,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTRight {
    flex: 0 0 auto;
    width: auto !important;
    background-color: transparent !important;
    padding: 0 !important;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTRight a,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTRight a,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTRight a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    /* deliberate: muted slate-500 resting, darken on hover — better close
       affordance than the §8.5 source (dark resting → muted hover). */
    color: #64748b;
    background-color: transparent;
    border-radius: 4px;
    text-decoration: none;
    cursor: pointer;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTRight a img,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTRight a img,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTRight a img {
    display: none !important;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTRight a::before,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTRight a::before,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTRight a::before {
    content: "";
    display: block;
    width: 16px;
    height: 16px;
    /* Reuse the shared --icon-x token (tokens.css:633) rather than inlining a
       Lucide SVG. The token bakes stroke='black', but a mask only samples
       alpha, so the colour comes from background-color (currentColor here). */
    background-color: currentColor;
    -webkit-mask: var(--icon-x) no-repeat center / 16px;
            mask: var(--icon-x) no-repeat center / 16px;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modTRight a:hover,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modTRight a:hover,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modTRight a:hover {
    color: var(--text-primary);
    background-color: var(--surface-muted);
}

/* §9.11.6 — Body: drop the slate-50 fill, 16px side gutter, dark text. These
   are confirm dialogs, so the body is just a one-line message. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modMain,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modMain,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modMain {
    background-color: transparent !important;
    border: 0 !important;
    padding: 0 16px !important;
    color: var(--text-primary);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px;
    line-height: 20px;
}

/* §9.11.7 — Footer: strip the gray band, flex-end pill cluster, 12px gap, 12px
   above + 16px below. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 {
    background-color: transparent !important;
    border: 0 !important;
    padding: 12px 16px 16px 16px !important;
    display: flex !important;
    justify-content: flex-end;
    align-items: center;
    gap: 12px;
    text-align: right;
}

/* §9.11.8 — Footer buttons → §9.10 dialog pills: primary teal, secondary
   neutral ghost, 36h / 8px radius / 14px-500. !important beats MainWhiteout
   .LinkButton. Drop the &nbsp; gaps' effect; hide the LinkButton <ins> spacer. */
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2 a.LinkButton,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2 a.LinkButton,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    height: 36px;
    min-width: 64px;
    margin: 0 !important;
    padding: 0 16px !important;
    border-radius: 8px !important;
    background-color: var(--primary) !important;
    color: #ffffff !important;
    border: 1px solid var(--primary) !important;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px !important;
    font-weight: 500 !important;
    line-height: 1 !important;
    text-decoration: none !important;
    box-shadow: none !important;
    position: static !important;
    cursor: pointer;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2 a.LinkButton:hover,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2 a.LinkButton:hover,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton:hover {
    background-color: var(--button-primary-hover) !important;
    border-color: var(--button-primary-hover) !important;
    color: #ffffff !important;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2 a.LinkButton.Secondary,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2 a.LinkButton.Secondary,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton.Secondary {
    background-color: #ffffff !important;
    color: #0f172a !important;
    border: 1px solid #e5e5e5 !important;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2 a.LinkButton.Secondary:hover,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2 a.LinkButton.Secondary:hover,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton.Secondary:hover {
    background-color: #f1f5f9 !important;
    border-color: #e5e5e5 !important;
    color: #0f172a !important;
}
body.sidebar-nav [id$='pnlCancelIncompletePendingChanges'] .modContainerStd .modFooter2 a.LinkButton > ins,
body.sidebar-nav [id$='pnlCancelConfirm'] .modContainerStd .modFooter2 a.LinkButton > ins,
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton > ins {
    display: none !important;
}

/* §9.11.9 — Delete dialog confirm ("Yes" = lbConfirmDeleteYes) is a destructive
   action — paint it a red pill (DESIGN.md §16.7) so it reads distinct from the
   neutral ghost "No", rather than a teal primary that invites a careless click.
   id-ends-with so the naming-container prefix is tolerated. */
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton[id$='lbConfirmDeleteYes'] {
    background-color: #dc2626 !important;
    border-color: #dc2626 !important;
    color: #ffffff !important;
}
body.sidebar-nav [id$='pnlDeleteConfirm'] .modContainerStd .modFooter2 a.LinkButton[id$='lbConfirmDeleteYes']:hover {
    background-color: #b91c1c !important;
    border-color: #b91c1c !important;
    color: #ffffff !important;
}
