/* Global app-level safety overrides loaded after vendor and module CSS. */

/* Validation belongs to Build Daily, not Bootstrap. Keep field ownership and
   accessible error state, but never paint Bootstrap's check/exclamation SVGs
   or its green "valid" treatment. */
@layer bd-validation {
  html body .bd-validation-message {
    display: none;
    width: 100%;
    margin-top: .25rem;
    color: var(--bd-theme-fg-b42318, #b42318);
    font-size: .72rem;
    font-weight: 700;
    line-height: 1.35;
  }

  html body :is(.bd-invalid, [aria-invalid="true"]) ~ .bd-validation-message,
  html body :is(.bd-invalid, .bd-has-error) .bd-validation-message,
  html body .bd-was-validated :invalid ~ .bd-validation-message,
  html body .bd-validation-message.d-block {
    display: block;
  }

  html body :is(input, select, textarea, .form-control, .form-select, .ts-wrapper).bd-invalid,
  html body :is(input, select, textarea, .form-control, .form-select, .ts-wrapper)[aria-invalid="true"],
  html body .bd-was-validated :is(input, select, textarea):invalid {
    border-color: var(--bd-theme-border-b42318, #b42318) !important;
  }

  /* TomSelect keeps the authored select in the DOM and inserts its visible
     control immediately after it. Carry server/browser invalid state across
     that seam without teaching every modal a one-off selector. */
  html body select.bd-invalid + .ts-wrapper .ts-control,
  html body select[aria-invalid="true"] + .ts-wrapper .ts-control,
  html body .bd-was-validated select:invalid + .ts-wrapper .ts-control {
    border-color: var(--bd-theme-border-b42318, #b42318) !important;
  }

  html body :is(.form-control, textarea.form-control).bd-invalid,
  html body .bd-was-validated :is(.form-control, textarea.form-control):invalid {
    padding-left: .75rem;
    background-image: none !important;
  }

  html body .form-select.bd-invalid,
  html body .bd-was-validated .form-select:invalid {
    --bs-form-select-bg-icon: none;
    padding-left: 2.25rem;
    background-image: var(--bs-form-select-bg-img) !important;
    background-position: left .75rem center;
    background-size: 16px 12px;
  }

  html body :is(.form-control, .form-select, .form-check-input).bd-valid,
  html body .bd-was-validated :is(.form-control, .form-select, .form-check-input):valid {
    border-color: var(--bd-theme-border-d0d5dd, #d0d5dd);
    box-shadow: none;
  }

  html body :is(.form-control, textarea.form-control).bd-valid,
  html body .bd-was-validated :is(.form-control, textarea.form-control):valid {
    padding-left: .75rem;
    background-image: none !important;
  }

  html body .form-select.bd-valid,
  html body .bd-was-validated .form-select:valid {
    --bs-form-select-bg-icon: none;
    padding-left: 2.25rem;
    background-image: var(--bs-form-select-bg-img) !important;
    background-position: left .75rem center;
    background-size: 16px 12px;
  }
}

/* Text links stay neutral, including visited links and Bootstrap color utilities.
   A named important layer keeps module/HTMX styles from restoring vendor purple.
   Controls retain their own foregrounds so filled buttons and selected tabs stay
   readable. The accent-text token is contrast-adjusted for light/dark themes. */
@layer bd-text-links {
  /* Link affordance is the pointer and theme hover color, never an underline.
     Include descendants: search results contain badges, marks, and icons with
     their own cursor/decoration rules. */
  html body :is(a, [role="link"], .btn-link),
  html body :is(a, [role="link"], .btn-link) * {
    text-decoration: none !important;
  }

  html body :is(a[href], a[hx-get], a[hx-post], [role="link"], .btn-link):not(:where(
    :disabled, .disabled, [aria-disabled="true"],
    .disabled *, [aria-disabled="true"] *
  )),
  html body :is(a[href], a[hx-get], a[hx-post], [role="link"], .btn-link):not(:where(
    :disabled, .disabled, [aria-disabled="true"],
    .disabled *, [aria-disabled="true"] *
  )) * {
    cursor: pointer !important;
  }

  html body :is(a, .btn-link):not(:where(
    .btn:not(.btn-link), .bd-btn, [class*="-btn"], [class*="button"],
    .std-btn-sample, .std-action,
    .bd-action-strip__btn, .portal-work-action, .svc-workon-command,
    .bd-btn-promote, [role="button"],
    .badge, .bd-badge, .bd-work-link-badge,
    .nav-link, .dropdown-item, .page-link, [role="tab"], [role="menuitem"],
    .active, .is-active, [aria-current], [aria-disabled="true"], .disabled,
    .nav *, .navbar *, .vertical-menu *, #sidebar-menu *,
    .bd-module-nav *, .bd-module-subnav *, .bd-settings-subnav *
  )) {
    color: inherit !important;
  }

  html body :is(a, .btn-link):not(:where(
    .btn:not(.btn-link), .bd-btn, [class*="-btn"], [class*="button"],
    .std-btn-sample, .std-action,
    .bd-action-strip__btn, .portal-work-action, .svc-workon-command,
    .bd-btn-promote, [role="button"],
    .badge, .bd-badge, .bd-work-link-badge,
    .nav-link, .dropdown-item, .page-link, [role="tab"], [role="menuitem"],
    .active, .is-active, [aria-current], [aria-disabled="true"], .disabled,
    .nav *, .navbar *, .vertical-menu *, #sidebar-menu *,
    .bd-module-nav *, .bd-module-subnav *, .bd-settings-subnav *
  )):is(:hover, :focus-visible) {
    color: var(--bd-theme-accent-text, var(--bs-body-color, #343a40)) !important;
  }
}

/* Beat Discovery's html body .bd-card > .table-responsive corner mask.
   :where() gave the old safety rule zero specificity, so overflow:hidden won.
   Keep higher-specificity open-dropdown escapes and vertical scrolling intact. */
html body :is(
  .table-responsive,
  .table-responsive-sm,
  .table-responsive-md,
  .table-responsive-lg,
  .table-responsive-xl,
  .table-responsive-xxl,
  .bd-table-responsive,
  .std-table-demo,
  .bd-scroll-x,
  .bd-hscroll,
  .bd-table-shell__scroll,
  .bd-table-wrap,
  .bd-table-scroll,
  .acct-table-wrap,
  .acct-table-shell,
  .inv-table-wrap,
  .settings-table-wrapper,
  [data-table-scroll],
  [data-std-table-shell],
  [data-ap-table-shell],
  [data-ar-table-shell],
  [data-acct-table-shell],
  [class$="-table-wrap"],
  [class*="-table-wrap"]
):not([data-bd-table-scroll="off"]) {
  max-width: 100% !important;
  min-width: 0 !important;
  overflow-x: auto !important;
  -webkit-overflow-scrolling: touch !important;
  overscroll-behavior-x: contain;
  /* Let vertical wheel/trackpad scrolling continue into the page at boundaries. */
  overscroll-behavior-y: auto !important;
  touch-action: auto;
  scrollbar-width: thin;
}

body :where(.bd-table-shell, .acct-table-shell) {
  max-width: 100% !important;
  min-width: 0 !important;
}

body :where(
  .table-responsive,
  .table-responsive-sm,
  .table-responsive-md,
  .table-responsive-lg,
  .table-responsive-xl,
  .table-responsive-xxl,
  .bd-table-responsive,
  .std-table-demo,
  .bd-table-shell__scroll,
  .bd-table-wrap,
  .bd-table-scroll,
  .acct-table-wrap,
  .acct-table-shell,
  .inv-table-wrap,
  .settings-table-wrapper,
  [data-table-scroll],
  [data-std-table-shell],
  [data-ap-table-shell],
  [data-ar-table-shell],
  [data-acct-table-shell],
  [class$="-table-wrap"],
  [class*="-table-wrap"]
) > :where(table, .table, .bd-table, .acct-table) {
  width: max-content;
  min-width: 100%;
  margin-bottom: 0 !important;
}

/* Fallback for older surfaces that put a table directly in a card/panel without
   a .table-responsive wrapper. CSS cannot create a wrapper, so the immediate
   container becomes the horizontal scroll host. */
html body :is(
  .bd-card,
  .card,
  .bd-subcard,
  .bd-tab-card__table,
  .std-work-panel,
  .modal-body,
  .offcanvas-body,
  .tab-pane
):has(> :is(table, .table, .bd-table, .acct-table)):not([data-bd-table-scroll="off"]) {
  max-width: 100% !important;
  min-width: 0 !important;
  overflow-x: auto !important;
  -webkit-overflow-scrolling: touch !important;
  overscroll-behavior-x: contain;
  /* Let vertical wheel/trackpad scrolling continue into the page at boundaries. */
  overscroll-behavior-y: auto !important;
  touch-action: auto;
}

body :where(
  .bd-card,
  .card,
  .bd-subcard,
  .bd-tab-card__table,
  .std-work-panel,
  .modal-body,
  .offcanvas-body,
  .tab-pane
):has(> :where(table, .table, .bd-table, .acct-table)) > :where(table, .table, .bd-table, .acct-table) {
  width: max-content;
  min-width: 100%;
}

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

.menu-title, .bd-chip { text-transform: none !important; }

.text-uppercase, .menu-title, .bd-chip { letter-spacing: normal !important; }

.ts-wrapper { min-width: 0; }
.ts-wrapper .ts-control {
  min-height: 38px;
  border: 1px solid var(--bd-theme-border-strong, #111) !important;
  border-radius: .5rem !important;
  padding: .28rem 2rem .28rem .6rem !important;
  background: var(--bd-theme-surface, #fff) !important;
  color: var(--bd-theme-text, #111827) !important;
  box-shadow: none !important;
  font-size: .84rem;
}
.ts-wrapper.single .ts-control { cursor: pointer; }
.ts-wrapper.single:not(.no-caret) .ts-control::after {
  content: "\F0140";                       /* mdi-chevron-down */
  font-family: "Material Design Icons";
  position: absolute;
  right: .5rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 1.05rem;
  line-height: 1;
  color: var(--bd-theme-text-muted, #667085);
  pointer-events: none;
}
.ts-wrapper.single.dropdown-active .ts-control::after { content: "\F0143"; } /* chevron-up */
.ts-wrapper.focus .ts-control { outline: 2px solid var(--bd-theme-accent, #111); outline-offset: 1px; }
.ts-wrapper.disabled .ts-control { opacity: .55; cursor: default; }

.ts-dropdown {
  border: 1px solid var(--bd-theme-border-strong, #111) !important;
  border-radius: .5rem !important;
  background: var(--bd-theme-surface, #fff) !important;
  color: var(--bd-theme-text, #111827) !important;
  box-shadow: 0 .5rem 1.2rem var(--bd-theme-shadow-0f172a-24, rgba(15,23,42,.14)) !important;
  margin-top: 2px;
}
.ts-dropdown .option { padding: .4rem .55rem; font-size: .82rem; }
.ts-dropdown .option.active,
.ts-dropdown .option:hover { background: var(--bd-theme-accent-soft, #eef3f8) !important; color: var(--bd-theme-text, #111827) !important; }
.ts-dropdown .no-results { padding: .5rem .55rem; color: var(--bd-theme-text-muted, #667085); font-size: .8rem; }

/* A single-value select is an input, not a selected-token rail. The value stays
   plain inside the control; bordered removable rectangles belong to multi-selects. */
.ts-wrapper.single .ts-control > .item {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 100%;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  color: inherit !important;
  font: inherit !important;
  line-height: 1.35 !important;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ts-wrapper.multi .ts-control > .item {
  border: 1px solid var(--bd-theme-border, #d0d5dd) !important;
  border-radius: .375rem !important;
  background: var(--bd-theme-surface-muted, #f8fafc) !important;
  color: var(--bd-theme-text, #111827) !important;
  font-size: .76rem;
  font-weight: 800;
}

.bd-mask-shell { position: relative; display: inline-flex; align-items: center; width: 100%; }
.bd-mask-shell > i.mdi {
  position: absolute;
  left: .55rem;
  color: var(--bd-theme-text-muted, #667085);
  font-size: 1rem;
  line-height: 1;
  pointer-events: none;
}
.bd-mask-shell.is-trailing > i.mdi { left: auto; right: .55rem; }
.bd-mask-shell > .form-control.bd-masked-input,
.bd-mask-shell > .bd-input.bd-masked-input,
.bd-mask-shell > .bd-masked-input {
  width: 100%;
  /* discovery.css gives every .form-control compact !important padding.
     The decorated-input inset must win that cascade or typed text clips the
     leading MDI glyph. */
  padding-left: 2.1rem !important;
}
.bd-mask-shell.is-trailing > .form-control.bd-masked-input,
.bd-mask-shell.is-trailing > .bd-input.bd-masked-input,
.bd-mask-shell.is-trailing > .bd-masked-input {
  padding-left: .6rem !important;
  padding-right: 2.1rem !important;
}
.bd-num-align { text-align: right; font-variant-numeric: tabular-nums; }

/* ====================================================================== */
/* ROUNDED SURFACES KEEP THEIR CORNERS                                     */
/* ====================================================================== */
.bd-card > :first-child,
.card > :first-child,
.bd-tab-card > :first-child,
.std-work-shell > :first-child,
.std-mainstay > :first-child,
.estimate-list-shell > :first-child,
.bd-work-card > :first-child {
  border-top-left-radius: inherit !important;
  border-top-right-radius: inherit !important;
}

.bd-card > :last-child,
.card > :last-child,
.bd-tab-card > :last-child,
.std-work-shell > :last-child,
.std-mainstay > :last-child,
.estimate-list-shell > :last-child,
.bd-work-card > :last-child {
  border-bottom-left-radius: inherit !important;
  border-bottom-right-radius: inherit !important;
}

.bd-card > .bd-card-head + *,
.card > .card-header + *,
.std-work-shell > .std-work-shell__head + * {
  border-top-left-radius: 0 !important;
  border-top-right-radius: 0 !important;
}

.bd-table-wrap > table > thead > tr:first-child > th:first-child,
.table-responsive > table > thead > tr:first-child > th:first-child { border-top-left-radius: inherit !important; }
.bd-table-wrap > table > thead > tr:first-child > th:last-child,
.table-responsive > table > thead > tr:first-child > th:last-child { border-top-right-radius: inherit !important; }

/* ====================================================================== */
/* LOADING ACTIVITY USES A CIRCLE, NEVER A SPINNING PICTOGRAM              */
/* ====================================================================== */
.mdi.mdi-spin {
  animation: none !important;
}

.mdi.mdi-spin::before {
  content: "" !important;
  display: block;
  width: .9em;
  height: .9em;
  box-sizing: border-box;
  border: 2px solid color-mix(in srgb, currentColor 24%, transparent);
  border-top-color: currentColor;
  border-right-color: currentColor;
  border-radius: 50%;
  animation: bd-loading-circle-spin .72s linear infinite;
}

@keyframes bd-loading-circle-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .mdi.mdi-spin::before { animation: none; }
}

/* ====================================================================== */
/* APP-WIDE LABELED ACTION CONTRACT                                        */
/* ====================================================================== */
/*
 * /standards/ defines one geometry for ordinary labeled actions regardless
 * of whether an older surface calls the component .btn, .bd-btn, or
 * .std-btn-sample. Keep row action strips and choice cards on their own
 * contracts; this adapter removes the visible size/radius drift everywhere
 * else, including HTMX fragments and modal footers.
 */
html body :is(.btn, .bd-btn, .std-btn-sample):not(.bd-action-strip__btn):not(.std-action):not([hidden]):not(.d-none) {
  min-height: 36px !important;
  border-radius: .6rem !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: .42rem !important;
  padding: .42rem .72rem !important;
  font-weight: 800 !important;
  line-height: 1.2 !important;
}

html body :is(.btn-sm, .bd-btn-sm, .std-btn-sample.is-compact):not(.bd-action-strip__btn) {
  min-height: 32px !important;
  padding: .32rem .6rem !important;
  font-size: .78rem !important;
}

html body :is(.btn-lg, .bd-btn-lg, .std-btn-sample.is-touch):not(.bd-action-strip__btn) {
  min-height: 44px !important;
  padding: .55rem .85rem !important;
}

html body :is(.btn, .bd-btn, .std-btn-sample):not(.bd-action-strip__btn) > .mdi {
  flex: 0 0 auto;
  margin: 0 !important;
  font-size: 1rem;
  line-height: 1;
}

/* Preserve a single perimeter for genuine joined Bootstrap groups after the
 * global radius adapter above. */
html body .btn-group > :is(.btn, .bd-btn):not(:first-child):not(:last-child) {
  border-radius: 0 !important;
}
html body .btn-group > :is(.btn, .bd-btn):first-child:not(:last-child) {
  border-radius: .6rem 0 0 .6rem !important;
}
html body .btn-group > :is(.btn, .bd-btn):last-child:not(:first-child) {
  border-radius: 0 .6rem .6rem 0 !important;
}

html body :is(.btn, .bd-btn, .std-btn-sample):is(:disabled, [aria-disabled="true"], [aria-busy="true"]) {
  opacity: .55;
  cursor: default;
  pointer-events: none;
}

/* A footer is one toolbar. Local modal CSS may choose its layout, but it may
 * not silently invent another button height, radius, weight, or icon gap. */
html body .bdm2 .std-modal-foot :is(.btn, .bd-btn, .std-btn-sample),
html body .modal-footer :is(.btn, .bd-btn, .std-btn-sample) {
  min-height: 36px !important;
  border-radius: .6rem !important;
  padding: .42rem .72rem !important;
  font-weight: 800 !important;
  gap: .42rem !important;
}

@media (max-width: 767.98px), (pointer: coarse) {
  html body .bdm2 .std-modal-foot :is(.btn, .bd-btn, .std-btn-sample),
  html body .modal-footer :is(.btn, .bd-btn, .std-btn-sample) {
    min-height: 44px !important;
  }
}

/* Custom register scroll hosts use the same native gesture handoff. Keep this
   default low-specificity: authored phone cards and print layouts still win. */
body :where(.ana-report-table, .svc-table-scroll, .acct-register-frame,
  .cx-ledger-wrap, .crew-shell__scroll, .bd-wizard-register, .bd-table-flat-wrapper) {
  min-width:0;
  max-width:100%;
  overflow-x:auto;
  overscroll-behavior-x:contain;
  overscroll-behavior-y:auto;
  touch-action:auto;
  -webkit-overflow-scrolling:touch;
}

/* A labeled action is wider than an icon button. Preserve its complete label
   in every register, including hybrid touch/trackpad tablet browsing. */
html body .bd-action-strip .bd-action-strip__btn:has(.bd-action-strip__label) {
  flex:0 0 auto!important;
  width:auto!important;
  max-width:none!important;
  white-space:nowrap!important;
  padding-inline:10px!important;
}
/* BD semantic left accents have a straight edge across every module.
   Keep the existing right corners, color, width, and clipping behavior. */
html body :is(.bd-left-accent, [class*="bd-left-accent-"], .bd-section-alert, [data-bd-left-accent]) {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}
html body :is(.bd-left-accent, [class*="bd-left-accent-"], .bd-section-alert, [data-bd-left-accent])::before {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}

/* Module-owned accent cards follow the same straight-left contract. These
   selectors have an actual semantic left border; ordinary cards stay rounded. */
html body :is(
  .svc-map-cluster,
  [data-page="service-dispatch-board"] .dispatch-child-ticket,
  [data-page="service-dispatch-board"] .dispatch-conflict-row,
  .dispatch-review__person, .rax-callout,
  .geo-detected-zone, .geo-area-score.is-scored,
  .geo-target-card.is-active, .geo-state-option.is-active,
  .takeoff-scale-region-label, .takeoff-live-notice, .takeoff-rollup-grid__row,
  .acct-driver, .bd-schedule-update-card, .ana-section-kicker,
  [data-takeoff-id][data-mobile-view="cards"] #takeoff-table tr.takeoff-row,
  #estimate-correspondence-card .ec-message,
  .bd-screen-tour-popover .bd-screen-tour-lead,
  .mp-assignment-card, .mp-mobile-assignment, .mp-month-preview-item,
  .mp-hour-assignment, .bd-est-expanded-clean .bd-next-callout,
  .bd-source-envelope-setup .bd-source-note,
  .bd-chat-message[data-friday-mode="data"] .bd-friday-panel,
  .bd-chat-message[data-friday-mode="files"] .bd-friday-panel,
  .bd-chat-message[data-friday-mode="approval"] .bd-friday-panel,
  .bd-chat-message[data-friday-mode="error"] .bd-friday-panel
) {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}
html body .ana-section-kicker { background: var(--bd-theme-surface); }
