/* Arabic typography for the whole template (Vuexy reads --bs-font-sans-serif) */
:root,
[data-bs-theme='light'],
[data-bs-theme='dark'] {
  --bs-font-sans-serif: 'Cairo', 'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

body {
  font-feature-settings: 'tnum';
}

/* Numbers in tables and inputs stay left-to-right inside the RTL layout. Aligned to the physical right: with
   unicode-bidi: plaintext an Arabic header such as «الكمية» is a right-to-left paragraph, where "end" is the left. */
.num,
input[type='number'],
input.numeral,
td.num,
th.num {
  direction: ltr;
  unicode-bidi: plaintext;
  text-align: right;
}

.table td.num {
  white-space: nowrap;
}

/* DataTables' own CSS (loaded after this file) aligns every cell to its start, which is the left in these LTR number
   cells; keep figures and their headers on the right like the other columns. */
body table.dataTable thead th.num,
body table.dataTable tbody td.num,
body table.dataTable tfoot th.num,
body table.dataTable tfoot td.num {
  text-align: right;
}

/* DataTables keeps the sort-arrow space on the right as in LTR tables, but Vuexy draws the arrow on the left in RTL:
   move the space to the left so header labels line up with the values below them. */
[dir='rtl'] table.dataTable thead > tr > th.dt-orderable-asc,
[dir='rtl'] table.dataTable thead > tr > th.dt-orderable-desc,
[dir='rtl'] table.dataTable thead > tr > th.dt-ordering-asc,
[dir='rtl'] table.dataTable thead > tr > th.dt-ordering-desc {
  padding-right: 1.25rem;
  padding-left: 30px;
}

/* Long notes take only the width left over and end with «…» instead of widening the table past the card */
.table td.text-truncate {
  max-width: 0 !important;
}

/* Page header used by the system's screens */
.page-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.5rem;
}
.page-head h4 { margin: 0; }
.page-head .actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.table-sm-dense td, .table-sm-dense th { padding-block: 0.45rem; }
.text-debit { color: var(--bs-danger); }
.text-credit { color: var(--bs-success); }

@media print {
  .layout-menu, .layout-navbar, .content-footer, .no-print, .page-head .actions { display: none !important; }
  .layout-page { padding: 0 !important; }
  .card { box-shadow: none !important; border: 0 !important; }
  /* Tables print every row (app.js), so the pager, page size and «1 - 100 من …» do not belong on paper. */
  .dt-paging, .dt-length, .dt-info { display: none !important; }
  /* Paper is white: a screen page printed while the dark theme is on comes out in the light colours. */
  [data-bs-theme=dark] {
    color-scheme: light;
    --bs-body-bg: #fff; --bs-body-bg-rgb: 255, 255, 255;
    --bs-paper-bg: #fff; --bs-paper-bg-rgb: 255, 255, 255;
    --bs-body-color: #444050; --bs-body-color-rgb: 68, 64, 80;
    --bs-heading-color: #2f2b3d;
    --bs-secondary-color: #6d6b77; --bs-secondary-color-rgb: 109, 107, 119;
    --bs-border-color: #d1d0d4;
    --bs-base-color: #2f2b3d; --bs-base-color-rgb: 47, 43, 61;
  }
  [data-bs-theme=dark] .table-light { --bs-table-bg: #f3f2f5; --bs-table-color: #2f2b3d; }
}
/* Page numbers on printed screen pages; the invoice and voucher prints set their own @page and do not load this file. */
@page { @bottom-center { content: "صفحة " counter(page) " من " counter(pages); font-size: 9pt; } }

/* Vuexy Flatpickr / Typeahead inside the RTL forms */
.flatpickr-input[readonly] { background-color: var(--bs-paper-bg, var(--bs-body-bg)); cursor: pointer; }
.twitter-typeahead { width: 100%; }
.twitter-typeahead .tt-menu { right: 0; width: 100%; text-align: right; max-height: 18rem; overflow-y: auto; }

/* ASP.NET renders the validation summary even with no errors; show the alert box only when it has messages */
.validation-summary-valid { display: none; }

/* Every Select2 box looks and opens like Vuexy's AppSelect (Vue template): the list is a floating menu card with
   rounded items, the hovered item tinted grey and the chosen item in the primary colour.
   select2.css loads after this file, hence the body prefix. */
body .select2-container--default .select2-dropdown,
body .select2-container--default.select2-container--open .select2-dropdown--above,
body .select2-container--default.select2-container--open .select2-dropdown--below {
  border: 0;
  border-radius: var(--bs-border-radius);
  box-shadow: var(--bs-box-shadow-lg);
  overflow: hidden;
}
body .select2-container--open .select2-dropdown--below { margin-top: 0.25rem; }
body .select2-container--open .select2-dropdown--above { margin-top: -0.25rem; }
body .select2-container--default .select2-results > .select2-results__options {
  max-height: 18rem;
  margin-block: 0;
  padding-block: 0.5rem;
}
body .select2-container--default .select2-results__option {
  margin: 0.125rem 0.5rem;
  padding: 0.5rem 1rem;
  min-height: 2.375rem;
  border-radius: var(--bs-border-radius);
  color: var(--bs-heading-color);
  font-size: 0.9375rem;
}
body .select2-container--default .select2-results__option:first-child { margin-top: 0; }
body .select2-container--default .select2-results__option:last-child { margin-bottom: 0; }
body .select2-container--default .select2-results__option--highlighted[aria-selected] {
  background-color: var(--bs-select-dropdown-link-hover-bg);
  color: var(--bs-heading-color);
}
body .select2-container--default .select2-results__option[aria-selected=true],
body .select2-container--default .select2-results__option--highlighted[aria-selected=true] {
  background-color: rgba(var(--bs-primary-rgb), 0.16);
  color: var(--bs-primary);
}
body .select2-container--default .select2-results__message { color: var(--bs-secondary-color); }
/* The search box of long lists sits at the top of the menu as a Vuexy input */
body .select2-container--default .select2-search--dropdown { padding: 0.5rem 0.5rem 0; }
body .select2-container--default .select2-search--dropdown .select2-search__field {
  inline-size: 100%;
  margin: 0;
  padding: 0.4rem 0.875rem;
  border: var(--bs-border-width) solid var(--bs-select-border-color);
  border-radius: var(--bs-border-radius);
  outline: 0;
}
body .select2-container--default .select2-search--dropdown .select2-search__field:focus {
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 1px var(--bs-primary);
}
/* The arrow turns only while the menu is open, as in AppSelect (not merely on focus) */
body .select2-container--default.select2-container--focus:not(.select2-container--open) .select2-selection--single .select2-selection__arrow b { transform: none; }
body .select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b { transform: rotate(180deg); }

/* Table footer: rows-per-page box beside the page numbers */
.dt-container .dt-layout-end:has(> .dt-length) { flex-wrap: wrap; gap: 1rem; }

/* Drawer forms: the save / cancel buttons sit in a footer under the scrolling body */
.offcanvas-footer { padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); }

/* While a page loads its content is not shown (see _CommonMasterLayout and app.js): the menu and navbar stay, and
   the content fades in once its tables and inputs are in their final form, instead of flashing the raw page.
   visibility, not display: what is built while hidden still gets its real width (DataTables sizes its page numbers to
   it; with display:none the pager showed only «1» until the first click). */
html.page-loading .content-wrapper { visibility: hidden; }
.content-wrapper { animation: page-in 0.15s ease-out; }
@keyframes page-in { from { opacity: 0; } to { opacity: 1; } }

/* Row action buttons in tables and lists: Vuexy's small buttons draw a 13px icon, too small to aim at; use the icon size of
   Vuexy's own list pages (icon-only buttons), and a little smaller beside a label. */
:is(.table, .list-group) .btn-icon.btn-sm { block-size: 2.125rem; inline-size: 2.125rem; }
:is(.table, .list-group) .btn-icon.btn-sm .icon-base { --bs-icon-size: 1.25rem; block-size: 1.25rem; font-size: 1.25rem; inline-size: 1.25rem; }
:is(.table, .list-group) .btn-sm:not(.btn-icon) .icon-base { --bs-icon-size: 1rem; block-size: 1rem; font-size: 1rem; inline-size: 1rem; }

/* The system name «نظام المبيعات والمخازن» is longer than the template's: keep it on one line beside the logo */
#layout-menu .app-brand-text.demo { font-size: 1rem; white-space: nowrap; }

/* Invoice line tables (sales, purchases): tight cells and inputs so every column fits the card at desktop width
   (Vuexy's 1.25rem cell padding pushed the purchase lines to 1,580px). */
#lines :is(th, td) { padding-inline: 0.375rem; vertical-align: middle; }
#lines th { white-space: normal; line-height: 1.25; }
#lines .select2-container { min-width: 18rem; }
#lines input.form-control { min-width: 5rem; padding-inline: 0.5rem; }
#lines input.form-control:is(.pack, .cartons) { min-width: 4rem; }

/* ApexCharts draws its text and grid in fixed light-theme colours; take them from the theme so the charts read in dark
   mode too (CSS fill beats the SVG attributes, and follows a live theme switch). */
.apexcharts-text, .apexcharts-xaxis-label, .apexcharts-yaxis-label { fill: var(--bs-secondary-color) !important; }
.apexcharts-gridline, .apexcharts-xaxis-tick, .apexcharts-xaxis line { stroke: var(--bs-border-color) !important; }
/* Tooltips in reading order: «المبيعات (د.ع): 43,620,158», the number kept left to right */
.apexcharts-tooltip { direction: rtl; text-align: right; }
.apexcharts-tooltip-text-y-value { direction: ltr; unicode-bidi: isolate; }


/* ---------------------------------------------------------------------------------------------------------------
   Contrast of the purple (WCAG AA, 4.5:1 for text of this size). White on Vuexy's #7367f0 is 4.26:1, and the purple as
   text on its own tint 3.5:1 (3.2:1 on the dark cards). The fills take a touch deeper purple (4.7:1 under white) and
   purple text on tints — label and outline buttons, label badges — a deeper ink in light and a lighter one in dark
   (5:1 or more), so the look is the same and the words can be read.
   --------------------------------------------------------------------------------------------------------------- */
:root, [data-bs-theme=light] {
  --bs-primary: #6c60e8;
  --bs-primary-rgb: 108, 96, 232;
  --bs-link-color: #6c60e8;
  --bs-link-color-rgb: 108, 96, 232;
  --app-primary-ink: #574bcb;
}
[data-bs-theme=dark] {
  --bs-primary: #6c60e8;
  --bs-primary-rgb: 108, 96, 232;
  --app-primary-ink: #a39cf5;
}
.btn-label-primary, .btn-text-primary { --bs-btn-color: var(--app-primary-ink); --bs-btn-hover-color: var(--app-primary-ink); --bs-btn-active-color: var(--app-primary-ink); }
.btn-outline-primary { --bs-btn-color: var(--app-primary-ink); }
.bg-label-primary { color: var(--app-primary-ink) !important; }
[data-bs-theme=dark] .text-primary { color: var(--app-primary-ink) !important; }
[data-bs-theme=dark] .nav { --bs-nav-link-hover-color: var(--app-primary-ink); --bs-nav-tabs-link-active-color: var(--app-primary-ink); }
/* The chosen menu item: Vuexy fades the purple to 70 % at one end, where white text fell to 2.8:1. */
.menu-item.active > .menu-link:not(.menu-toggle),
:dir(rtl) .menu-item.active > .menu-link:not(.menu-toggle) { background: linear-gradient(-270deg, #6c60e8 0%, #5e52d1 100%); }

/* Keyboard focus: a clear ring on whatever the Tab key reaches (Vuexy shows almost none on buttons and links). Fields
   keep their own focus border, and the error list focused by the page itself (tabindex -1) shows none. */
:is(a, button, .btn, [role=button], [tabindex]:not([tabindex="-1"]), summary, .page-link, .select2-selection, .form-check-input):focus-visible,
.btn-check:focus-visible + .btn {
  outline: 2px solid var(--app-primary-ink);
  outline-offset: 2px;
  box-shadow: none;
}
/* «تخطَّ إلى المحتوى»: the first stop of the Tab key, shown only when reached. */
.skip-link:focus { position: fixed !important; top: 0.5rem; inset-inline-start: 0.5rem; z-index: 2000; }
#main:focus { outline: none; }
/* The keyboard sheet: the keys on one side, what they do on the other. */
.shortcut-list > div { display: flex; gap: 1rem; align-items: baseline; padding: 0.5rem 0; border-bottom: 1px solid var(--bs-border-color); }
.shortcut-list > div:last-child { border-bottom: 0; }
.shortcut-list dt { flex: 0 0 9.5rem; display: flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; font-weight: 400; }
.shortcut-list dd { margin: 0; }
.shortcut-list kbd { direction: ltr; unicode-bidi: isolate; }

/* ---------------------------------------------------------------------------------------------------------------
   Dark theme: neutral grey instead of Vuexy's navy, the purple accent kept. core.css is compiled from the template
   and cannot be rebuilt here, so its dark tokens are overridden below (this file loads after it, same specificity).
   Every colour is given with its -rgb twin, which Vuexy uses for rgba() mixes. The bg-label-* tints and the input
   borders are color-mix()es of these tokens and follow on their own.
   --------------------------------------------------------------------------------------------------------------- */
[data-bs-theme=dark] {
  --bs-body-bg: #16171b;
  --bs-body-bg-rgb: 22, 23, 27;
  --bs-paper-bg: #1e1f24;
  --bs-paper-bg-rgb: 30, 31, 36;
  --bs-body-color: #c4c7ce;
  --bs-body-color-rgb: 196, 199, 206;
  --bs-heading-color: #e4e6eb;
  --bs-base-color: #e4e6eb;
  --bs-base-color-rgb: 228, 230, 235;
  --bs-secondary-color: #9a9ea8;
  --bs-secondary-color-rgb: 154, 158, 168;
  --bs-secondary-bg: #9a9ea8;
  --bs-secondary-bg-rgb: 154, 158, 168;
  --bs-tertiary-color: rgba(196, 199, 206, 0.5);
  --bs-tertiary-color-rgb: 196, 199, 206;
  --bs-tertiary-bg: #2a2c33;
  --bs-tertiary-bg-rgb: 42, 44, 51;
  --bs-border-color: #2c2e35;
  --bs-border-color-translucent: rgba(255, 255, 255, 0.12);
  --bs-highlight-color: #e4e6eb;

  --bs-gray-25: #1b1c21;
  --bs-gray-50: #202127;
  --bs-gray-75: #24262c;
  --bs-gray-100: #2a2c33;
  --bs-gray-200: #2c2e35;
  --bs-gray-300: #3a3d46;
  --bs-gray-400: #50535d;
  --bs-gray-500: #6b6f7a;
  --bs-gray-600: #8a8e99;
  --bs-gray-700: #9a9ea8;
  --bs-gray-800: #b9bcc4;
  --bs-gray-900: #e4e6eb;
  --bs-gray: #8a8e99;
  --bs-gray-rgb: 138, 142, 153;
  --bs-light: #2a2c33;
  --bs-light-rgb: 42, 44, 51;
  --bs-dark: #5a5d66;
  --bs-dark-rgb: 90, 93, 102;

  /* Bootstrap's static subtle colours: paper mixed with each colour, as Vuexy computes them (84% / 61%). */
  --bs-primary-bg-subtle: #2c2b45;
  --bs-secondary-bg-subtle: #2e2f35;
  --bs-success-bg-subtle: #203a30;
  --bs-info-bg-subtle: #19383f;
  --bs-warning-bg-subtle: #423429;
  --bs-danger-bg-subtle: #42262b;
  --bs-light-bg-subtle: #232429;
  --bs-dark-bg-subtle: #2a2b30;
  --bs-primary-border-subtle: #3f3b74;
  --bs-secondary-border-subtle: #444650;
  --bs-success-border-subtle: #226141;
  --bs-info-border-subtle: #125b68;
  --bs-warning-border-subtle: #765130;
  --bs-danger-border-subtle: #763136;
  --bs-light-border-subtle: #33353c;
  --bs-dark-border-subtle: #3a3c44;
  --bs-secondary-text-emphasis: #b9bcc4;
  --bs-light-text-emphasis: #c4c7ce;
  --bs-dark-text-emphasis: #e4e6eb;

  /* Shadows in plain black: the navy-tinted ones read as a blue halo on grey. */
  --bs-box-shadow: 0 0.1875rem 0.75rem 0 rgba(0, 0, 0, 0.28);
  --bs-box-shadow-xs: 0 0.0625rem 0.375rem 0 rgba(0, 0, 0, 0.22);
  --bs-box-shadow-sm: 0 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.25);
  --bs-box-shadow-lg: 0 0.25rem 1.125rem 0 rgba(0, 0, 0, 0.32);
  --bs-box-shadow-xl: 0 0.3125rem 1.875rem 0 rgba(0, 0, 0, 0.36);
  --bs-floating-component-shadow: 0 0.31rem 1.25rem 0 rgba(0, 0, 0, 0.45);

  /* The side menu: these are fixed colours in core.css, not derived from the paper. */
  --bs-menu-bg: #1e1f24;
  --bs-menu-bg-rgb: 30, 31, 36;
  --bs-menu-color: #d0d3d9;
  --bs-menu-color-rgb: 208, 211, 217;
  --bs-menu-hover-color: #e4e6eb;
  --bs-menu-sub-active-color: #e4e6eb;
  --bs-menu-horizontal-active-bg: #2c2b45;
  --bs-menu-box-shadow: 0 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.25);
}
[data-bs-theme=dark] .pagination { --bs-pagination-color: #e4e6eb; --bs-pagination-bg: #26282e; }
[data-bs-theme=dark] .list-group { --bs-list-group-color: #e4e6eb; }
[data-bs-theme=dark] .accordion { --bs-accordion-btn-color: #e4e6eb; --bs-accordion-active-color: #e4e6eb; }
[data-bs-theme=dark] .avatar { --bs-avatar-initial-bg: #2a2c33; }
[data-bs-theme=dark] .modal-backdrop { --bs-backdrop-bg: #0b0c0e; }
[data-bs-theme=dark] .offcanvas-backdrop,
[data-bs-theme=dark] .layout-overlay { background-color: #0b0c0e; }
[data-bs-theme=dark] .swal2-container.swal2-backdrop-show { background: rgba(11, 12, 14, 0.6); }
/* Section totals and opening-balance rows (Daily, Book, Statement): a quiet band, not core.css's light grey. */
[data-bs-theme=dark] .table-light {
  --bs-table-color: var(--bs-heading-color);
  --bs-table-bg: #26282e;
  --bs-table-border-color: #33353c;
  --bs-table-striped-bg: #2a2c33;
  --bs-table-active-bg: #2a2c33;
  --bs-table-hover-bg: #2a2c33;
  --bs-table-striped-color: var(--bs-table-color);
  --bs-table-active-color: var(--bs-table-color);
  --bs-table-hover-color: var(--bs-table-color);
}
.apexcharts-legend-text { color: var(--bs-secondary-color) !important; }
/* Input outlines at 3:1 against the card (WCAG non-text contrast): Vuexy's 22% mix gives 1.9:1, too faint to see where
   to type on grey. Focus and validation colours still win. */
[data-bs-theme=dark] :is(.form-control, .form-select):not(:focus):not(:disabled):not(.is-invalid):not(.is-valid) { border-color: #67696f; }
[data-bs-theme=dark] .select2-container { --bs-select-border-color: #67696f; }
[data-bs-theme=dark] .input-group { --bs-input-group-addon-border-color: #67696f; }
/* Cards and the body are both dark grey; a hairline edge keeps them apart where a shadow no longer shows. */
[data-bs-theme=dark] .card { --bs-card-border-width: 1px; --bs-card-border-color: #2a2c33; }

/* Search-list entries in two lines: the name, then what tells similar names apart (App.personOption / itemOption). */
.picker-option { line-height: 1.35; }
.picker-option .picker-title { font-weight: 500; }
.picker-option .picker-details { display: block; margin-top: 0.125rem; }
.select2-results__option--highlighted .picker-option .text-body-secondary { color: inherit !important; opacity: 0.8; }

/* Filter cards (app.js filterCard): the folded card on phones, the chips of the filters in use, empty tables. */
.filter-toggle { display: none; }
@media (max-width: 767.98px) {
  .filters-foldable .filter-toggle { display: flex; justify-content: center; align-items: center; }
  .filters-foldable:not(.filters-open) :is(form[data-filters], .filter-tools) { display: none !important; }
  .filters-foldable.filters-open .filter-toggle { margin-bottom: 1rem; }
}
.filter-chips .badge { font-size: 0.8125rem; padding: 0.4rem 0.65rem; }
.filter-chips .badge a { text-decoration: none; font-size: 1rem; line-height: 1; opacity: 0.7; }
.filter-chips .badge a:hover { opacity: 1; }
.dt-is-empty :is(.dt-paging, .dt-info, .dt-length) { display: none !important; }
@media print {
  .filter-chips .badge { background: none !important; border: 1px solid #bbb; color: #000 !important; }
}

/* Invoice lines on a phone: one card per line instead of a table scrolling sideways (app.js stackLabels). */
@media (max-width: 767.98px) {
  table[data-stack] thead { display: none; }
  table[data-stack], table[data-stack] tbody { display: block; }
  table[data-stack] tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem 0.75rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--bs-border-color); }
  table[data-stack] td { display: block; border: 0 !important; padding: 0 !important; min-width: 0; }
  table[data-stack] td[data-label]:not([data-label=""])::before { content: attr(data-label); display: block; font-size: 0.75rem; color: var(--bs-secondary-color); margin-bottom: 0.125rem; }
  table[data-stack] td.stack-wide { grid-column: 1 / -1; }
  table[data-stack] td:empty { display: none; }
  #lines .select2-container, #lines input.form-control { min-width: 0 !important; width: 100% !important; }
}
/* Purchase lines: the two sale-price columns show on demand («أسعار البيع»). */
#lines.hide-sale-prices .sale-col { display: none !important; }
/* Dashboard cards that open what they count (a stretched link) show it on hover and keyboard focus. */
.card-link { transition: box-shadow 0.15s ease-in-out, transform 0.15s ease-in-out; }
.card-link:hover, .card-link:focus-within { box-shadow: var(--bs-box-shadow-lg); transform: translateY(-2px); }
.card-link .card-body { position: relative; }
.card-link .card-body a:not(.stretched-link) { position: relative; z-index: 2; }
/* Report cells of text (customer, item) on one line, cut, the whole value in the tooltip; on paper they wrap. */
#report td.cell-text { max-width: 14rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media print { #report td.cell-text { white-space: normal; max-width: none; } }
/* Phones: the save buttons of the sales, purchase and voucher forms stay at the bottom of the screen, in one row,
   instead of after the whole form; the page leaves room for them. */
@media (max-width: 767.98px) {
  .form-actions {
    position: fixed; inset-inline: 0; bottom: 0; z-index: 1050;
    display: flex !important; gap: 0.5rem; padding: 0.625rem 1rem calc(0.625rem + env(safe-area-inset-bottom));
    background: var(--bs-paper-bg); box-shadow: 0 -0.25rem 1rem rgba(0, 0, 0, 0.12);
  }
  .form-actions .btn { flex: 1 1 0; padding-inline: 0.5rem; font-size: 0.8125rem; }
  .form-actions .btn:not(:first-child) { flex-grow: 0.7; }
  .form-actions kbd, .form-actions .btn-lg { font-size: 0.8125rem; }
  .form-actions kbd { display: none; }
  .content-wrapper:has(.form-actions) { padding-bottom: 4.5rem; }
}
/* The wide report keeps its first column in sight while it scrolls sideways. */
#report th:first-child, #report td:first-child { position: sticky; inset-inline-start: 0; z-index: 1; background: var(--bs-paper-bg); }
/* Sales scan box: its result list over the lines, the quantity box small; the totals strip stays in sight. */
/* A choice the server refused (FormErrors): the whole button group framed, as a single field would be. */
[role=radiogroup].is-invalid { outline: 1px solid var(--bs-form-invalid-border-color); outline-offset: 3px; border-radius: var(--bs-border-radius); }
.scan-results { z-index: 1060; max-height: 22rem; overflow-y: auto; top: calc(100% + 0.25rem); background: var(--bs-paper-bg); border-radius: var(--bs-border-radius); }
.scan-results .list-group-item { background: var(--bs-paper-bg); border-inline: 0; }
.scan-results .list-group-item.active { background: rgba(var(--bs-primary-rgb), 0.12); color: var(--bs-heading-color); border-color: transparent; }
.scan-qty { width: 6.5rem; }
.sticky-totals { position: sticky; bottom: 0; z-index: 3; background: var(--bs-paper-bg); border-top: 1px solid var(--bs-border-color); }
@media (max-width: 767.98px) { .sticky-totals { bottom: 4.25rem; } }
tr.line.flash { animation: line-flash 1.2s ease-out; }
@keyframes line-flash { from { background: rgba(var(--bs-success-rgb), 0.22); } to { background: transparent; } }
