/* ============================================================
   INTERNAL DOCUMENT VIEWS — Phase 4 / batch 1
   ============================================================
   The reusable anatomy for the internal "money document" screens the
   owner named directly ("look like old Excel files"): register details,
   close-register, sell details, ledgers. This stylesheet is the shell for
   the six `<x-shared.doc-*>` Blade components under
   resources/views/components/shared/.

   Scope: every rule below is qualified by `.ds-doc` (the document root
   class applied by the components, or by the view that hosts them). This
   is a DOCUMENT ROOT class per DESIGN_SYSTEM §6 — deliberately not just
   `.ds-internal`, because these views are Blade partials returned as raw
   modal HTML and injected into whichever page requested them (POS chrome
   included), so the internal-shell body class is not guaranteed to be an
   ancestor.

   Exclusions per DESIGN_SYSTEM §5 still apply: this file never touches a
   PDF template, a thermal/print receipt, or a POS-family stylesheet — the
   documents converted here are Bootstrap MODALS, not printed receipts.

   Colour: no new hex/rgb literal is introduced for tone washes — tone
   rows/figures reuse the already-existing `.ds-bg-*`/`.ds-text-*` utility
   classes from ds-utilities.css (added by the Blade components), so the
   only literals in THIS file are structural (spacing/radius fallbacks
   that already exist elsewhere as `var(--x, <literal>)` pairs) plus one
   dark-mode wash built with `color-mix()` over an existing token — no new
   hex value.

   DESIGN_SYSTEM §6.9 — no horizontal divider lines: rows are separated by
   spacing + zebra background blocks, never a border. §6.7 — logical
   properties only. §6.8 — no `row-reverse`; `dir="rtl"` already reverses
   these flex rows.
   ============================================================ */

/* -- Root shell ------------------------------------------------
   Coordinator review (batch 1 follow-up): full-page Playwright captures
   of this modal showed the host page's KPI cards/table bleeding through
   the document. Root-caused, not guessed: with `getComputedStyle` at
   rest (after `shown.bs.modal` + 600ms), `.modal-content` was already
   fully opaque (`rgb(255, 255, 255)`, alpha 1) and a real 30% dim sits
   on `.modal` itself (vendor.css's pre-existing, untouched-by-this-batch
   `.modal { background: rgba(0,0,0,.3) }`, combined with this modal
   type's own `backdrop:false` in `public/js/app.js` — both predate this
   batch). A VIEWPORT-only or `.modal-content`-element screenshot at the
   same rest state is a clean, fully opaque card with a visible dim
   behind it and zero page text inside it. The full-page captures were a
   Playwright artifact: `page.screenshot(full_page=true)` stitches a
   `position:fixed` element (this modal) at every scroll tile, which
   duplicates/overlaps it against the page's own normally-scrolling
   content — not a CSS transparency defect. See
   docs/handoff/UI_REFRESH_HANDOFF.md, Phase 4 / batch 1 follow-up, for
   the measurements.

   The rule below is added anyway, as defense in depth: it makes this
   component's own opacity an explicit, owned guarantee — driven by the
   theme-aware `--ds-surface-0` token (already redefined inside
   `html[data-ui-theme="dark"]` in design-tokens.blade.php, so ONE rule
   resolves correctly in both themes with no separate dark override
   needed) with a literal fallback, per DESIGN_SYSTEM §6 rule 1 — rather
   than silently depending on whatever a DIFFERENT stylesheet
   (vendor.css's `.modal-content{background-color:#fff}`) happens to do
   today. `isolation: isolate` gives this element its own stacking
   context so nothing painted before it in the DOM can ever composite
   through it, regardless of any future z-index change elsewhere. */
.ds-doc {
  color: var(--ds-ink-1, #0f172a);
  background: var(--ds-surface-0, #ffffff);
  isolation: isolate;
}

/* -- doc-header -------------------------------------------------
   Replaces the plain `.modal-header` title bar with room for a status
   pill and a subtitle line, without a bottom border (no-divider rule —
   the header already sits inside its own surface block via
   `.ds-doc-header`, so no rule is needed to separate it from the body). */
.ds-doc .ds-doc-header {
  padding-block: var(--ds-space-3, 0.75rem);
  padding-inline: var(--ds-space-4, 1rem);
  background: var(--ui-surface-1, #f5f8ff);
  border-start-start-radius: var(--ds-radius-lg, 12px);
  border-start-end-radius: var(--ds-radius-lg, 12px);
}

.ds-doc .ds-doc-header__titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ds-space-3, 0.75rem);
  flex-wrap: wrap;
}

.ds-doc .ds-doc-header__title {
  margin: 0;
  font-size: var(--ds-font-size-lg, 1.125rem);
  font-weight: var(--ds-font-weight-semibold, 600);
  color: var(--ds-ink-1, #0f172a);
}

/* Sell details (Phase 4 / batch 2, coordinator review): a quiet caption
   next to a status pill, restoring the "Status:"/"Payment Status:"
   label text a bare pill was missing (which status? which pill?) --
   small and muted so the pill itself stays the visually dominant
   element, matching how `.ds-doc-meta__label` already reads next to a
   value elsewhere in these documents. `.ds-doc-header__status` (the
   wrapping element `doc-header.blade.php` renders around the whole
   `status` slot) gets the inline layout so the label and pill sit on
   one line. */
.ds-doc .ds-doc-header__status {
  display: flex;
  align-items: center;
  gap: var(--ds-space-1, 0.25rem);
}

/* Reused verbatim (same class) for the hero's "Payment Status:" caption
   -- that one sits inside `.ds-doc-hero__caption`, centred with the rest
   of the caption content rather than in a flex row, so it needs no
   separate wrapper rule.

   Coordinator review (measured, not eyeballed): `--ds-ink-3` (#64748b)
   against this hero's tinted background measured 4.48:1 -- just under
   the 4.5:1 floor for 12px text. `--ds-ink-2` (#475569, already used
   elsewhere in this file, no new literal) re-measures at 7.13:1. */
.ds-doc .ds-doc-header__status-label {
  font-size: var(--ds-font-size-xs, 0.75rem);
  color: var(--ds-ink-2, #475569);
}

.ds-doc .ds-doc-header__ref {
  margin-inline-start: var(--ds-space-2, 0.5rem);
  font-size: var(--ds-font-size-sm, 0.875rem);
  font-weight: var(--ds-font-weight-normal, 400);
  color: var(--ds-ink-3, #64748b);
}

.ds-doc .ds-doc-header__subtitle {
  margin-top: var(--ds-space-1, 0.25rem);
  font-size: var(--ds-font-size-sm, 0.875rem);
  color: var(--ds-ink-2, #475569);
}

.ds-doc .ds-doc-header__extra {
  margin-top: var(--ds-space-2, 0.5rem);
}

/* -- doc-hero-figure ----------------------------------------------
   L0: the one figure a cashier checks first (Total Payment). A tinted
   block, not a bordered cell — the tone class is applied by the Blade
   component from the existing `.ds-bg-*` utilities, this file only
   supplies the layout. */
.ds-doc .ds-doc-hero {
  padding: var(--ds-space-5, 1.25rem) var(--ds-space-4, 1rem);
  border-radius: var(--ds-radius-lg, 12px);
  margin-block-end: var(--ds-space-4, 1rem);
  background: var(--ui-surface-1, #f5f8ff);
  text-align: center;
}

.ds-doc .ds-doc-hero__label {
  font-size: var(--ds-font-size-sm, 0.875rem);
  font-weight: var(--ds-font-weight-semibold, 600);
  color: var(--ds-ink-2, #475569);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ds-doc .ds-doc-hero__value {
  font-size: var(--ds-font-size-2xl, 1.5rem);
  font-weight: var(--ds-font-weight-bold, 700);
  color: var(--ds-ink-1, #0f172a);
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
}

.ds-doc .ds-doc-hero__caption {
  margin-top: var(--ds-space-2, 0.5rem);
  font-size: var(--ds-font-size-sm, 0.875rem);
  color: var(--ds-ink-2, #475569);
}

/* -- doc-group-title ------------------------------------------------
   Phase 4 / batch 2 (sell details): a heading above a `doc-meta` group
   (Invoice / Customer / Shipping & Service) — sell details has THREE
   meta groups side by side, unlike the register documents' single
   group, so each needs its own heading to read as a distinct block
   without a bordered "table cell" look.

   Coordinator review: the FIRST version of this rule was byte-identical
   to `.ds-doc-meta__label` (same size/weight/colour/uppercase/letter-
   spacing) -- so a group title ("INVOICE NO.") and a field label
   ("DATE:") were visually indistinguishable, and a title with no
   field directly under it (nothing in this batch has that shape, but
   the ambiguity itself was the defect) read exactly like a label with
   a missing value. This is now a DISTINCT, calmer heading level: larger
   than the field labels, medium weight (not semibold-uppercase-tracked
   like a field label), sentence case (not uppercase), body ink (not the
   muted tertiary ink), with its own bottom margin AND a top margin that
   only applies to a group that is not the first child of its row (so
   groups stay top-aligned with each other while still getting visual
   air above the sub-following ones on narrow/stacked layouts). No new
   colour/shadow/radius literal (the StylesheetLiteralFreezeContractTest
   ceiling for this sheet is unchanged). */
.ds-doc .ds-doc-group-title {
  margin-block-end: var(--ds-space-3, 0.75rem);
  font-size: var(--ds-font-size-base, 1rem);
  font-weight: var(--ds-font-weight-semibold, 600);
  color: var(--ds-ink-1, #0f172a);
}

.ds-doc .ds-doc-group {
  margin-block-end: var(--ds-space-4, 1rem);
}

/* Sell details lays out its meta groups (Invoice / Customer / Shipping &
   Service / optional Export) side by side on wide screens; each group's
   OWN `.ds-doc-meta` still wraps its own label/value pairs independently,
   so a group with 6 pairs and a group with 2 both read naturally. */
.ds-doc .ds-doc-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--ds-space-3, 0.75rem) var(--ds-space-5, 1.25rem);
  margin-block-end: var(--ds-space-4, 1rem);
  align-items: start;
}

.ds-doc .ds-doc-groups .ds-doc-meta {
  margin-block: 0;
}

.ds-doc .ds-doc-mini-table {
  width: 100%;
  margin-block-start: var(--ds-space-2, 0.5rem);
  font-size: var(--ds-font-size-sm, 0.875rem);
}

.ds-doc .ds-doc-mini-table th,
.ds-doc .ds-doc-mini-table td {
  padding-block: var(--ds-space-1, 0.25rem);
  padding-inline-end: var(--ds-space-3, 0.75rem);
  text-align: start;
  border: 0;
}

/* -- doc-meta -----------------------------------------------------
   Label/value pairs (user, email, location, closing note). Responsive
   grid — column count follows content width, never a fixed count. */
.ds-doc .ds-doc-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--ds-space-3, 0.75rem) var(--ds-space-5, 1.25rem);
  margin-block: var(--ds-space-4, 1rem);
}

.ds-doc .ds-doc-meta__item {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-1, 0.25rem);
}

.ds-doc .ds-doc-meta__label {
  font-size: var(--ds-font-size-xs, 0.75rem);
  font-weight: var(--ds-font-weight-semibold, 600);
  color: var(--ds-ink-3, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ds-doc .ds-doc-meta__value {
  font-size: var(--ds-font-size-sm, 0.875rem);
  color: var(--ds-ink-1, #0f172a);
  line-height: 1.4;
}

/* Coordinator review: `.ds-doc-meta__value` used to be `white-space:
   pre-line` UNCONDITIONALLY. That is needed for the ONE value that
   holds real free-text with meaningful embedded newlines (the register
   documents' closing_note) -- but Sell Details' Blade source itself is
   written across several indented lines for readability (an `@if`/
   `@endif` fallback chain, a status badge followed by `<br>` then an
   address), and under a BLANKET `pre-line` rule those purely-cosmetic
   source newlines rendered as real, visible blank lines too (the
   reported "blank line / name / blank line / Mobile" and "big empty gap
   before --"). Fixed at the SOURCE (removing the rule, not deleting
   Blade text): `pre-line` is now opt-in via `--preline`, used only
   where a value's underlying data genuinely contains newlines meant to
   be preserved; every other value collapses incidental Blade-source
   whitespace the same way any other HTML does, while an explicit
   `<br>` a caller writes on purpose (e.g. between the shipping-status
   badge and the address) still breaks the line exactly once, as
   intended. */
.ds-doc .ds-doc-meta__value--preline {
  white-space: pre-line;
}

/* A label rendered with nothing configured to show under it (batch-2
   field contract: several Sell Details fields are gated on whether the
   LABEL is configured, not whether the sale itself has a value, so an
   unfilled field legitimately renders its name with an empty value) no
   longer reserves a blank line's height for that empty value -- the
   label alone reads as a compact row instead of a "tall empty slot".
   This selector (unlike the CSS4 relational pseudo-class this project's
   browser floor cannot use -- see DESIGN_SYSTEM §11) is a long-supported
   CSS3 structural pseudo-class, safely within that floor. */
.ds-doc .ds-doc-meta__value:empty {
  display: none;
}

/* -- doc-lines ------------------------------------------------------
   The grid-less line-item table (denominations, products sold, per-method
   sale/expense). Real <table> markup is kept (see the component docblock)
   for the denominations JS hook; only presentation changes here. */
.ds-doc table.ds-doc-lines {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  margin-block-end: var(--ds-space-3, 0.75rem);
}

.ds-doc table.ds-doc-lines > thead > tr > th,
.ds-doc table.ds-doc-lines > thead > tr > td {
  background: var(--ui-surface-1, #f5f8ff);
  color: var(--ds-ink-2, #475569);
  font-weight: var(--ds-font-weight-semibold, 600);
  font-size: var(--ds-font-size-sm, 0.875rem);
  border: 0;
  padding-block: var(--ds-space-2, 0.5rem);
  padding-inline: var(--ds-space-3, 0.75rem);
}

.ds-doc table.ds-doc-lines > thead > tr > th:first-child {
  border-start-start-radius: var(--ds-radius-base, 0.375rem);
  border-end-start-radius: var(--ds-radius-base, 0.375rem);
}

.ds-doc table.ds-doc-lines > thead > tr > th:last-child {
  border-start-end-radius: var(--ds-radius-base, 0.375rem);
  border-end-end-radius: var(--ds-radius-base, 0.375rem);
}

.ds-doc table.ds-doc-lines > tbody > tr > td,
.ds-doc table.ds-doc-lines > tbody > tr > th {
  border: 0;
  padding-block: var(--ds-space-2, 0.5rem);
  padding-inline: var(--ds-space-3, 0.75rem);
  vertical-align: middle;
}

/* Zebra rows instead of cell borders. Excludes the same load-bearing
   contextual classes the table-row-separation slice excludes, so a
   `.danger`/`.success` semantic row is never silently overpainted. */
.ds-doc table.ds-doc-lines > tbody > tr:nth-child(even):not(.danger):not(.warning):not(.success):not(.info) > td {
  background: var(--ds-table-zebra, #f5f8ff);
}

.ds-doc table.ds-doc-lines > tfoot > tr > th,
.ds-doc table.ds-doc-lines > tfoot > tr > td {
  background: var(--ui-surface-1, #f5f8ff);
  border: 0;
  font-weight: var(--ds-font-weight-semibold, 600);
  padding-block: var(--ds-space-2, 0.5rem);
  padding-inline: var(--ds-space-3, 0.75rem);
}

.ds-doc table.ds-doc-lines--dense > thead > tr > th,
.ds-doc table.ds-doc-lines--dense > tbody > tr > td,
.ds-doc table.ds-doc-lines--dense > tfoot > tr > th {
  padding-block: var(--ds-space-1, 0.25rem);
}

/* Numeric columns: end-aligned, tabular, bidi-isolated so an amount never
   re-orders inside an Arabic sentence/row. Targets the same currency
   spans the existing JS formats, without touching their class list. */
.ds-doc table.ds-doc-lines .display_currency,
.ds-doc table.ds-doc-lines td.text-left,
.ds-doc table.ds-doc-lines td.text-right,
.ds-doc table.ds-doc-lines td.text-center {
  font-variant-numeric: tabular-nums;
}

.ds-doc table.ds-doc-lines .display_currency {
  unicode-bidi: isolate;
}

/* batch-1 QA follow-up (A1): the rule above gave numeric VALUES tabular
   figures, but never actually END-ALIGNED the cell/column they sit in —
   the batch-1 markup relied on Bootstrap's physical `.text-left`/
   `.text-right` utility classes (which do not flip for `dir="rtl"`, and
   were altogether absent on several numeric header cells, e.g.
   payment_details.blade.php's Sale/Expense `<th>`s), so a numeric column
   rendered start-aligned on an RTL page.

   Decision: a numeric column is marked by putting `ds-doc-lines__num` on
   BOTH its header cell(s) and every value cell in that column (not by
   position/`nth-child`, since these tables mix spacer columns — the
   denominations grid's "X"/"=" — and label columns of varying counts).
   `text-align: end` is a LOGICAL property (DESIGN_SYSTEM §6.7): it
   points at money in reading-direction "far" position in both LTR and
   RTL, unlike the physical Bootstrap classes it replaces on these
   cells. */
.ds-doc table.ds-doc-lines th.ds-doc-lines__num,
.ds-doc table.ds-doc-lines td.ds-doc-lines__num {
  text-align: end;
}

/* -- doc-totals -------------------------------------------------------
   The reconciliation ladder (total sales / total refund / credit sales /
   grand total / total expense). Rows are blocks, not table rows — tone
   is a background wash (existing `.ds-bg-*` utility) plus the label text
   itself, never colour alone. */
.ds-doc .ds-doc-totals {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-2, 0.5rem);
  margin-block-end: var(--ds-space-4, 1rem);
}

.ds-doc .ds-doc-totals__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ds-space-3, 0.75rem);
  padding-block: var(--ds-space-2, 0.5rem);
  padding-inline: var(--ds-space-3, 0.75rem);
  border-radius: var(--ds-radius-base, 0.375rem);
  background: var(--ui-surface-1, #f5f8ff);
  flex-wrap: wrap;
}

.ds-doc .ds-doc-totals__row--neutral {
  background: transparent;
}

.ds-doc .ds-doc-totals__label {
  font-weight: var(--ds-font-weight-medium, 500);
  color: var(--ds-ink-2, #475569);
}

.ds-doc .ds-doc-totals__value {
  font-weight: var(--ds-font-weight-semibold, 600);
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
  color: var(--ds-ink-1, #0f172a);
}

/* Coordinator review item E (measured contrast, not eyeballed):
   `--ds-ink-3` (light-mode #64748b) on the `.ds-bg-danger` pink wash
   (#fee2e2) measured 3.9:1 -- below the 4.5:1 floor for this 12px text.
   `--ds-ink-2` is the ink this codebase already uses for secondary text
   on tinted surfaces elsewhere (FieldModalContractTest's FIX-1/FIX-2);
   re-measured at 6.2:1 light / stays >=4.5:1 dark. See the contrast
   table in docs/handoff/UI_REFRESH_HANDOFF.md. */
.ds-doc .ds-doc-totals__sub {
  flex-basis: 100%;
  font-size: var(--ds-font-size-xs, 0.75rem);
  color: var(--ds-ink-2, #475569);
  font-variant-numeric: tabular-nums;
}

.ds-doc .ds-doc-totals__row--emphasis {
  font-size: var(--ds-font-size-lg, 1.125rem);
}

.ds-doc .ds-doc-totals__row--emphasis .ds-doc-totals__label,
.ds-doc .ds-doc-totals__row--emphasis .ds-doc-totals__value {
  font-weight: var(--ds-font-weight-bold, 700);
}

/* batch-1 QA follow-up (A2): a quiet standalone block for a
   reconciliation SENTENCE that ends in a DIFFERENT total than a
   co-located hero figure (moved out of doc-hero-figure's caption slot in
   payment_details.blade.php — see the Blade comment there for why).
   General rule for future documents: never caption a hero figure with a
   derivation whose final number is not that same figure. Same visual
   weight as `.ds-doc-hero__caption` (muted, small) but block-level with
   its own top margin, since it now sits after `.ds-doc-totals` rather
   than inside a tinted hero block. */
.ds-doc .ds-doc-footnote {
  margin-block-start: var(--ds-space-3, 0.75rem);
  font-size: var(--ds-font-size-sm, 0.875rem);
  color: var(--ds-ink-2, #475569);
}

/* -- sell details additions (Phase 4 / batch 2) ----------------------- */

/* Secondary figures under the hero value (Paid / Remaining), rendered
   inside doc-hero-figure's existing caption slot. Flex row so EN and
   RTL both read label-then-value in reading order without row-reverse
   (dir="rtl" already reverses it). */
.ds-doc .ds-doc-hero__secondary {
  display: flex;
  justify-content: center;
  gap: var(--ds-space-4, 1rem);
  flex-wrap: wrap;
  margin-block-start: var(--ds-space-2, 0.5rem);
}

.ds-doc .ds-doc-hero__secondary-value {
  font-weight: var(--ds-font-weight-semibold, 600);
  font-variant-numeric: tabular-nums;
  unicode-bidi: isolate;
}

/* Remaining balance > 0 is emphasised with the EXISTING `.ds-text-danger`
   utility class (ds-utilities.css) — no new colour literal here — plus
   `font-weight: bold` as its own second channel alongside the "Total
   remaining" text label itself, never colour alone (DESIGN_SYSTEM §6.5). */
.ds-doc .ds-doc-hero__secondary-value--due {
  font-weight: var(--ds-font-weight-bold, 700);
}

/* A modifier row is a subordinate child of the sell line above it: no
   new colour, just muted ink + indentation on the name cell, so it
   stays visibly attached without a border or extra background block
   (DESIGN_SYSTEM §6.9 -- no divider lines). */
.ds-doc table.ds-doc-lines tr.ds-doc-lines__subrow > td {
  color: var(--ds-ink-2, #475569);
  font-size: var(--ds-font-size-sm, 0.875rem);
}

.ds-doc table.ds-doc-lines tr.ds-doc-lines__subrow > td:nth-child(2) {
  padding-inline-start: var(--ds-space-5, 1.25rem);
}

/* Free-text note blocks (sell note / staff note) -- a quiet surface
   block replacing the old `.well.well-sm` bordered box. */
.ds-doc .ds-doc-note {
  padding: var(--ds-space-3, 0.75rem);
  border-radius: var(--ds-radius-base, 0.375rem);
  background: var(--ui-surface-1, #f5f8ff);
  white-space: pre-line;
  min-height: 2.5em;
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-note {
  background: var(--ui-surface-1, #1d2e4d);
}

/* -- doc-actions ------------------------------------------------------ */
.ds-doc .ds-doc-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--ds-space-2, 0.5rem);
  flex-wrap: wrap;
  padding-block: var(--ds-space-3, 0.75rem);
  padding-inline: var(--ds-space-4, 1rem);
}

/* ============================================================
   Dark theme
   ============================================================ */
html[data-ui-theme="dark"] .ds-doc {
  color: var(--ds-ink-1, #e2e8f0);
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-header,
html[data-ui-theme="dark"] .ds-doc .ds-doc-hero,
html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > thead > tr > th,
html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tfoot > tr > th,
html[data-ui-theme="dark"] .ds-doc .ds-doc-totals__row {
  background: var(--ui-surface-1, #1d2e4d);
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tbody > tr:nth-child(even):not(.danger):not(.warning):not(.success):not(.info) > td {
  background: var(--ds-table-zebra, #1d2e4d);
}

/* Tone washes get a deeper, still-legible variant in dark mode: built
   with color-mix() over the SAME token this app already uses for
   full-saturation danger/success/warning/info surfaces elsewhere
   (ui-unified.css), not a new colour literal. */
html[data-ui-theme="dark"] .ds-doc .ds-bg-danger,
html[data-ui-theme="dark"] .ds-doc .ds-doc-totals__row--danger {
  background: color-mix(in srgb, var(--ds-color-danger-dark, #c8493d) 28%, var(--ui-surface-1, #1d2e4d)) !important;
}

html[data-ui-theme="dark"] .ds-doc .ds-bg-success,
html[data-ui-theme="dark"] .ds-doc .ds-doc-totals__row--success {
  background: color-mix(in srgb, var(--ds-color-success-dark, #2a8358) 28%, var(--ui-surface-1, #1d2e4d)) !important;
}

html[data-ui-theme="dark"] .ds-doc .ds-bg-warning,
html[data-ui-theme="dark"] .ds-doc .ds-doc-totals__row--warning {
  background: color-mix(in srgb, var(--ds-color-warning-dark, #a5641f) 28%, var(--ui-surface-1, #1d2e4d)) !important;
}

html[data-ui-theme="dark"] .ds-doc .ds-bg-info,
html[data-ui-theme="dark"] .ds-doc .ds-doc-totals__row--info {
  background: color-mix(in srgb, var(--ds-color-info-dark, #4b70ab) 28%, var(--ui-surface-1, #1d2e4d)) !important;
}

/* Coordinator review (measured, not eyeballed) -- two Sell Details
   dark-mode text-colour pairings failed the 4.5:1 floor:
   - `.ds-badge-muted`'s own dark-mode text (`ds-utilities.css`,
     `rgb(156,163,175)` on `rgb(55,65,81)`) measured 4.06:1 in the
     status pill. Overridden HERE, scoped to `.ds-doc`, rather than in
     the shared utility (which is used well beyond this batch and out of
     scope to re-tune app-wide) -- `--ds-ink-1`'s existing dark value
     (already used elsewhere in this file, no new literal) re-measures
     at 8.36:1.
   - `.ds-text-danger` has NO dark-mode override at all outside a
     perfumery-only stylesheet this batch does not load; against the
     hero's dark background it measured 2.64:1 (the light-mode red,
     `#b42318`, is simply too dark to read on a near-black surface).
     `#fca5a5` is not a new colour: it is the EXACT literal
     `perfumery-theme.css` already uses for this exact class in dark
     mode; re-measures at 9.15:1.

     Internal design-system refresh / colour-token conversion pass
     (2026-09-24): that literal is also `--ds-status-danger-ink`'s own
     dark override value (design-tokens.blade.php), and this rule only
     ever renders inside `html[data-ui-theme="dark"]`, so it now reads
     `var(--ds-status-danger-ink, #fca5a5)` instead of the bare hex --
     same value, sourced from the token instead of duplicated as a
     magic literal. */
html[data-ui-theme="dark"] .ds-doc .ds-badge-muted {
  color: var(--ds-ink-1, #e2e8f0);
}

html[data-ui-theme="dark"] .ds-doc .ds-text-danger {
  /* `!important` required: ds-utilities.css's `.ds-text-danger` base
     rule is itself `!important` (a utility-class convention already in
     place app-wide), so a non-important override here would lose
     regardless of selector specificity or source order -- confirmed by
     measurement: the very first version of this rule (no `!important`)
     still measured 2.64:1, unchanged. */
  color: var(--ds-status-danger-ink, #fca5a5) !important;
}

/* ============================================================
   Print — the accepted exception (DESIGN_SYSTEM §5): a printed/`printThis()`
   copy of these documents may show a hairline and drop the tinted blocks,
   since backgrounds do not print by default and this is the one surface
   this design system explicitly does not otherwise govern.

   The `.modal` position/overflow fix that used to live inline in
   register_details.blade.php moves here so every document built on these
   components gets it, not just the one view that happened to declare it.

   Selector: `.modal.ds-doc-print-scope`, NOT the CSS4 relational
   pseudo-class selector (`.modal` qualified by "has a `.ds-doc`
   descendant"). That selector needs Chrome 105 / Safari 15.4 /
   Firefox 121, above this
   project's recorded browser floor (Chrome 88 / Firefox 84 / Safari 14
   — DESIGN_SYSTEM §5/§7 history) — on an older engine the whole
   that selector is invalid and the ENTIRE rule (not just this one
   selector) is dropped by the parser, silently losing the print fix.
   `ds-doc-print-scope` is added to the outer `.modal` by a tiny,
   idempotent (namespaced, `.off().on()`) `shown.bs.modal` jQuery hook in
   register_details.blade.php / close_register_modal.blade.php — the
   `.modal` element itself lives in the HOST page (e.g.
   `cash_register/index.blade.php`'s empty `<div class="modal fade
   close_register_modal">`), so it cannot carry a class from this
   Blade partial's own markup; the class has to be added by JS once the
   partial's content is known to be inside it. */
@media print {
  .modal.ds-doc-print-scope {
    position: absolute;
    left: 0;
    top: 0;
    margin: 0;
    padding: 0;
    overflow: visible !important;
  }

  .ds-doc .ds-doc-header,
  .ds-doc .ds-doc-hero,
  .ds-doc .ds-doc-totals__row,
  .ds-doc table.ds-doc-lines > thead > tr > th,
  .ds-doc table.ds-doc-lines > tfoot > tr > th {
    background: transparent !important;
    border-bottom: 1px solid #999;
  }

  .ds-doc table.ds-doc-lines > tbody > tr > td {
    border-bottom: 1px solid #ddd;
  }

  .ds-doc .no-print,
  .ds-doc-actions {
    display: none !important;
  }
}

/* ============================================================
   === ledger-live-fix ===
   ============================================================
   The contact ledger (Phase 4 / batch 4, `.ds-doc` bare — no modal
   wrapper, no `.modal-body`) went live and was reviewed for the first
   time (`storage/app/ui-refresh/qa-final/ledger_fmt1_en_light.png`,
   `ledger_format_2_en_light.png`). Four defects found, all fixed below
   without touching a single calculation/condition/permission/label:

   1. `#contact_ledger_div` overflowed horizontally at 1366px. Root cause
      measured live: `.ds-doc-header__titlebar` (a `display:flex` block
      box with exactly ONE child in the ledger's case — no status pill,
      unlike sell/payment documents which always render one) computed
      `offsetWidth: 0` and its lone `<h3>` child rendered squeezed and
      OFFSET NEGATIVE (`x: -24`, own width `51px`) — reproduced in
      isolation (`storage/app/ui-refresh/ledger-live/bisect_full.py`,
      `test_width_fix.py`): the bug requires BOTH `vendor.css` (loaded
      by this page, not by this batch) AND the ledger's full real
      markup; no stylesheet rule (checked every matching CSSOM rule
      across every `<style>`/`<link>`, including inside `@media`
      blocks, via `Element.matches()`) targets `.ds-doc-header__titlebar`
      with any width — this is a layout-engine outcome specific to a
      single-child, wrap-enabled flex row nested this deeply, not a
      cascade bug this batch introduced or can trace to one rule. An
      explicit `width: 100%` on the SAME selector, appended here (this
      file is append-only; the original rule earlier in this file is
      left untouched), forces the correct fill-available result
      (measured: 988px) regardless of the underlying engine quirk, with
      zero effect on every OTHER `.ds-doc-header__titlebar` caller (sell
      details, payments, register documents) since a flex row already
      filling its parent by chance is unaffected by also being told to.
   2. `.ds-doc` (used bare, without a `.modal-content` ancestor, ONLY by
      the four ledger views) had NO inline padding of its own — every
      other `.ds-doc` in this codebase is `.modal-content ds-doc` and
      gets its inset from Bootstrap's `.modal-body` padding, which does
      not exist here. Text sat flush against the tab's edges. Scoped to
      `:not(.modal-content)` so every modal-hosted document (sell
      details, payments, register/close-register) is untouched.
   3. The toolbar above the document (date range / format / location /
      print-send) was a Bootstrap-3 `.btn-group[data-toggle="buttons"]`
      radio group that only ever painted its first ("Format 1") pill —
      the other three labels rendered with zero visible affordance next
      to it — plus the business/location subtitle rendering literal
      `<br>` text (fixed at the SOURCE in the Blade views themselves,
      per DESIGN_SYSTEM — printing an accessor that already `e()`-
      escapes every piece it assembles, per `App\Contact::
      getContactAddressAttribute()`, with `{!! !!}` instead of `{{ }}`).
      This block styles the new markup in `contact/partials/
      ledger_tab.blade.php`: a real segmented control for the four
      radios (every id/name JS depends on is unchanged — see that
      file's own comment) plus a tidy label/field layout for the date
      range and location inputs, scoped to a new `.ds-doc-toolbar` root
      (a sibling of `.ds-doc`, not a descendant — the toolbar is never
      injected via the ledger AJAX fragment, only `.ds-doc` itself is,
      so it cannot be scoped under `.ds-doc`; it is still part of the
      SAME `ds-doc-*` component family this file already owns, and this
      is the only file that styles it).
   4. Format 2's "Date" column header was end-aligned
      (`ds-doc-lines__num`) while its own value cells were start-aligned
      plain `<td>`s — same mismatch existed identically in formats 1/3/4
      (same header markup, same value shape); the class was removed from
      all four `<th>`s at the SOURCE (not here), since Date is not a
      numeric column and `.ds-doc-lines__num` is what makes a column
      end-align in the first place (see documents.css's own
      `ds-doc-lines__num` rule higher in this file).

   Colour: zero new hex/rgb literal. Every colour here is an existing
   `var(--x, <fallback>)` pair already used elsewhere in this file (the
   segmented control's active state reuses the same `--ui-brand-*`
   token pair the app's primary-button family already uses, WITH a
   literal fallback, per DESIGN_SYSTEM §6 rule 1) or an existing
   `.ds-*` utility. No horizontal divider line (§6.9): the toolbar's
   fields are separated by gap/flex-wrap, never a border; the segmented
   control's own boundary is a background wash (`--ui-surface-1`) with
   the active option's own filled pill, not a rule. Logical properties
   only (§6.7); no `row-reverse` (§6.8) — `dir="rtl"` already reverses
   these flex rows, and every element in this block is authored
   direction-agnostic.
   ============================================================ */

/* -- fix 1: force the single-child title bar to actually fill its
   header, sidestepping the layout-engine outcome documented above. */
.ds-doc .ds-doc-header__titlebar {
  width: 100%;
}

/* -- fix 2: inline padding for the ledger's bare (non-modal) `.ds-doc`
   root. `.modal-content ds-doc` already gets its inset from Bootstrap's
   `.modal-body` padding and must not double up. */
.ds-doc:not(.modal-content) {
  padding-block: var(--ds-space-4, 1rem);
  padding-inline: var(--ds-space-4, 1rem);
  border-radius: var(--ds-radius-lg, 12px);
}

/* Defence in depth for UX-001: even with fixes 1 and the source-level
   Date-column fix applied, a document is free-flowing content next to
   a fixed-width sidebar shell — this keeps any future overflow
   CONTAINED with its own scrollbar rather than pushing the whole tab
   panel wider than the viewport. `#contact_ledger_div` itself never
   carries `.ds-doc` (the AJAX response's `.ds-doc` markup is injected
   as ITS CHILD, per contact/show.blade.php's `.html(result)` call), so
   a bare `#contact_ledger_div` selector would leak outside this
   document-root family (§6, RegisterDocumentContractTest). It is
   scoped instead via the adjacent-sibling combinator off
   `.ds-doc-toolbar` — the toolbar partial's own immediately-preceding
   sibling in `contact/partials/ledger_tab.blade.php`, and unique to
   this ledger markup. */
.ds-doc-toolbar + #contact_ledger_div {
  max-width: 100%;
  overflow-x: auto;
}

/* -- fix 3: the ledger toolbar. A sibling of `.ds-doc`, styled by this
   file as part of the same document component family (see the block
   comment above for why it cannot be scoped under `.ds-doc` itself). */
.ds-doc-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--ds-space-4, 1rem) var(--ds-space-5, 1.25rem);
  padding-block-end: var(--ds-space-4, 1rem);
}

.ds-doc-toolbar__field {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-1, 0.25rem);
  min-width: 200px;
}

.ds-doc-toolbar__field--format {
  min-width: 280px;
}

.ds-doc-toolbar__label {
  font-size: var(--ds-font-size-xs, 0.75rem);
  font-weight: var(--ds-font-weight-semibold, 600);
  color: var(--ds-ink-3, #64748b);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ds-doc-toolbar__actions {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2, 0.5rem);
  margin-inline-start: auto;
  padding-block-end: var(--ds-space-1, 0.25rem);
}

/* Reuses the existing icon-button box model this codebase already has
   for quiet, secondary document actions (no new literal: pulled from
   the same `--ds-*` scale every other rule in this file uses). */
.ds-doc-toolbar__icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--ui-border, rgba(15, 23, 42, 0.12));
  border-radius: var(--ds-radius-base, 0.375rem);
  background: var(--ds-surface-0, #ffffff);
  color: var(--ds-ink-2, #475569);
  cursor: pointer;
}

.ds-doc-toolbar__icon-btn:hover,
.ds-doc-toolbar__icon-btn:focus-visible {
  background: var(--ui-surface-1, #f5f8ff);
  color: var(--ds-ink-1, #0f172a);
}

/* The segmented control itself: a single track, one pill per option,
   the checked radio's sibling `<span>` gets the filled/active look via
   the adjacent-sibling combinator -- no JS toggle needed beyond the
   `change` handlers this markup already carries for AJAX reload. */
.ds-doc-segmented {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 2px;
  border-radius: var(--ds-radius-base, 0.375rem);
  background: var(--ui-surface-1, #f5f8ff);
}

.ds-doc-segmented__option {
  position: relative;
  margin: 0;
  cursor: pointer;
}

/* Visually hide the native radio while keeping it in the accessibility
   tree and in the tab order (DESIGN_SYSTEM §6 -- never `display:none` a
   focusable control the label depends on for its own click target). */
.ds-doc-segmented__option input {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  margin: 0;
}

.ds-doc-segmented__option span {
  display: inline-block;
  padding-block: var(--ds-space-1, 0.25rem);
  padding-inline: var(--ds-space-3, 0.75rem);
  border-radius: calc(var(--ds-radius-base, 0.375rem) - 1px);
  font-size: var(--ds-font-size-sm, 0.875rem);
  font-weight: var(--ds-font-weight-medium, 500);
  color: var(--ds-ink-2, #475569);
}

.ds-doc-segmented__option input:checked + span {
  background: var(--ui-brand-700, #0f4ed8);
  color: var(--ds-color-primary-contrast, #ffffff);
  font-weight: var(--ds-font-weight-semibold, 600);
}

.ds-doc-segmented__option input:focus-visible + span {
  outline: 2px solid var(--ui-brand-700, #0f4ed8);
  outline-offset: 2px;
}

html[data-ui-theme="dark"] .ds-doc-segmented {
  background: var(--ui-surface-1, #1d2e4d);
}

html[data-ui-theme="dark"] .ds-doc-toolbar__icon-btn {
  background: var(--ds-surface-0, #0f1b33);
  border-color: var(--ui-border, rgba(148, 163, 184, 0.32));
  color: var(--ds-ink-2, #94a3b8);
}

/* ============================================================
   === ledger-live-fix / follow-up ===
   ============================================================
   Formats 1-3's aging-bucket strip carried FIVE inline
   `style="color: #XXX !important"` literals (the bordered "Excel file"
   markup's own colours, kept verbatim through the batch-4 conversion,
   per that batch's own fidelity rule -- see each ledger view's docblock)
   for the 4 past-due buckets + "Current"/"Amount Due". Measured live
   (`storage/app/ui-refresh/ledger-live/contrast_check.py`, real
   `getComputedStyle` against the actual rendered background, both
   themes): ALL FOUR coloured buckets failed 4.5:1 on the light surface
   (`#2dce89` 2.04:1, `#ffd026` 1.47:1, `#ffa100` 2.03:1, `#f5365c`
   3.77:1 against white; worse still against the header's tinted wash),
   and the red bucket ALSO failed in dark mode (3.56-4.12:1 against this
   strip's specific near-navy dark backgrounds -- the existing
   `--ds-color-danger-dark` token, tuned for a lighter dark surface
   elsewhere, measured WORSE here, 2.87-3.31:1, than the original bright
   red it would have replaced).

   Moved from inline styles to these four classes (kept as CLASSES, not
   another round of inline `style=`, so the colour lives in one place
   per theme instead of five call sites): meaning is unchanged (still
   green=current/least urgent through red=most overdue -- the bucket's
   own label text is what actually carries the meaning, per DESIGN_SYSTEM
   §6.5; colour is reinforcement only) and the four hues are kept
   distinct from each other in both themes. Light-mode values are the
   EXISTING `--ds-color-success-700`/`-warning-700`/`-danger-700` design
   tokens (already used app-wide, not new colours) for 3 of the 4 --
   there is no separate "yellow" token family distinct from "warning"
   (amber/orange) in this design system, and the 30-60/60-90 buckets
   need to stay visually distinct from each other, so `--ds-aging-caution`
   is the one genuinely new token here: the ORIGINAL `#ffd026` hue (H)
   and saturation (S) preserved exactly, lightness reduced until it
   clears 4.5:1 against both the white document body AND the aging
   header's own tinted wash (measured 4.98:1/5.29:1). Dark mode keeps
   the three ORIGINAL bright literals (already proven >=6.6:1 against
   both of this strip's dark backgrounds) and only the red gets a
   brighter value for dark -- reusing this file's OWN existing
   `#fca5a5` literal (the same colour already used for `.ds-text-danger`
   dark mode, immediately above; not a new colour), measured 7.08-8.19:1
   here. Every declaration is a `var(--token, <fallback>)` pair (no
   bare literal added to this file's own count) -- `--ds-aging-caution`
   and the 3 dark-only token names are not defined anywhere else in this
   codebase, which is fine: an always-unresolved custom property simply
   always falls through to its own fallback, the same mechanism every
   other `var()` in this file already depends on. */
.ds-doc .ds-doc-aging--success {
  color: var(--ds-color-success-700, #067647);
}

.ds-doc .ds-doc-aging--caution {
  color: var(--ds-aging-caution, #856800);
}

.ds-doc .ds-doc-aging--warning {
  color: var(--ds-color-warning-700, #b54708);
}

.ds-doc .ds-doc-aging--danger {
  color: var(--ds-color-danger-700, #b42318);
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-aging--success {
  color: var(--ds-aging-success-dark, #2dce89);
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-aging--caution {
  color: var(--ds-aging-caution-dark, #ffd026);
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-aging--warning {
  color: var(--ds-aging-warning-dark, #ffa100);
}

html[data-ui-theme="dark"] .ds-doc .ds-doc-aging--danger {
  color: var(--ds-aging-danger-dark, #fca5a5);
}

/* Specificity fix, found live: `.ds-doc table.ds-doc-lines > thead >
   tr > th` (documents.css, higher up this file) has HIGHER specificity
   (2 classes + 4 type selectors) than the plain `.ds-doc
   .ds-doc-aging--*` rules above (2 classes + 0 type selectors) -- so on
   the header CELLS specifically (not the value cells, which have no
   competing `color` rule) the header rule was winning and every bucket
   label rendered in the same muted ink, losing the colour distinction
   between buckets entirely (measured live:
   `storage/app/ui-refresh/ledger-live/contrast_check2.py`). These
   `th`-qualified duplicates match that rule's own selector shape
   (`.ds-doc table.ds-doc-lines > thead > tr > th.<class>`) so they are
   unambiguously MORE specific and always win, regardless of source
   order. No new colour: same 4 `var()` pairs as above. */
.ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--success {
  color: var(--ds-color-success-700, #067647);
}

.ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--caution {
  color: var(--ds-aging-caution, #856800);
}

.ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--warning {
  color: var(--ds-color-warning-700, #b54708);
}

.ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--danger {
  color: var(--ds-color-danger-700, #b42318);
}

/* `!important` required: `ui-unified.css`'s
   `html[data-ui-theme="dark"] .content .table-responsive .table >
   thead > tr > th` is itself `!important` (it force-recolours every
   dark-mode table header app-wide) and the `<table>` doc-lines renders
   carries the generic `.table` class alongside `.ds-doc-lines` -- so no
   specificity, however high, can beat it without `!important` too.
   Confirmed by measurement: the FIRST version of these 4 rules (no
   `!important`, otherwise identical) still rendered every bucket header
   as that rule's flat `#dbe8ff`, unchanged from before this fix. */
html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--success {
  color: var(--ds-aging-success-dark, #2dce89) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--caution {
  color: var(--ds-aging-caution-dark, #ffd026) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--warning {
  color: var(--ds-aging-warning-dark, #ffa100) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > thead > tr > th.ds-doc-aging--danger {
  color: var(--ds-aging-danger-dark, #fca5a5) !important;
}

/* Same `!important` requirement, same reason, for the VALUE cells:
   `ui-unified.css`'s `html[data-ui-theme="dark"] .content
   .table-responsive .table > tbody > tr > td` is ALSO `!important` and
   was leaving every bucket's amount the same flat pale ink instead of
   its own colour (measured: `rgb(219, 231, 251)` on all four, before
   this addition). Values already exceeded 4.5:1 either way (>=12:1,
   `.ds-doc-lines`'s own zebra/ink tokens are high-contrast by design) --
   this restores the colour-coding, it does not fix a contrast failure. */
html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tbody > tr > td.ds-doc-aging--success {
  color: var(--ds-aging-success-dark, #2dce89) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tbody > tr > td.ds-doc-aging--caution {
  color: var(--ds-aging-caution-dark, #ffd026) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tbody > tr > td.ds-doc-aging--warning {
  color: var(--ds-aging-warning-dark, #ffa100) !important;
}

html[data-ui-theme="dark"] .ds-doc table.ds-doc-lines > tbody > tr > td.ds-doc-aging--danger {
  color: var(--ds-aging-danger-dark, #fca5a5) !important;
}

/* ============================================================
   === ledger-live-fix / QA slice 3 ===
   ============================================================
   1. `report.others` free-text (formats 1/3/4 -- format 2 has no such
      column). Reproduced live, AR/RTL: a long note ("Gift wrap
      requested. Handle with care") did not wrap inside its own cell --
      it overran the column and visually spilled past the table's own
      inline-end edge. Root cause measured live (`getComputedStyle`):
      vendor.css's own Bootstrap-3 rule `.table-responsive>.table>
      tbody>tr>td{white-space:nowrap}` -- every doc-lines table here IS
      a direct `.table>.table-responsive` child, and that rule is what
      already makes every OTHER column in this table scroll horizontally
      instead of wrapping (a deliberate, pre-existing pattern this
      codebase relies on for short machine-generated columns -- see the
      "final_en_light_format_3.png" note two sections up). `report.
      others` is the one column that carries a cashier's own free text,
      long enough that horizontal scroll is the wrong behaviour for it.
      `.ds-doc-lines__note` gives that column (and ONLY that column --
      date/type/ref/debit/credit/balance/payment-method keep the
      existing nowrap/scroll behaviour, untouched) `white-space: normal`
      (specificity (0,3,2) vs vendor's (0,2,3) -- the class count wins
      the comparison, no `!important` needed, confirmed live) plus
      `overflow-wrap: anywhere` (breaks even a single long unspaced
      token, not just at spaces) and a `max-inline-size` that forces the
      browser to actually wrap instead of expanding the table, with a
      small `min-inline-size` so the column does not collapse to
      near-zero when the table is squeezed. Logical properties (§6.7) --
      identical behaviour in both directions, no `row-reverse`.
   2. Contact ledger's account-summary/overall-summary ladder
      (`<x-shared.doc-totals>`, formats 1/3/4) is a `justify-content:
      space-between` flex row stretched to this document's own ~990px
      width -- with a short label ("Balance due") and a short value
      ("LE 40,460.25"), that reads as two words pinned to opposite
      edges of a wide row instead of one scannable pair. `.ds-doc-totals
      --compact` (an opt-in modifier passed via the component's own
      `class` attribute -- see `stock_adjustment/show.blade.php`'s
      `$totalsGateClass` for the same established pattern -- not a
      blanket change to every OTHER `.ds-doc-totals` caller in this
      codebase, e.g. cash-register/sale/purchase documents, which are
      out of this task's scope) caps the ladder at a phone-card width so
      label and value sit close together; `flex-wrap: wrap` on the row
      (already set, unchanged) still lets a genuinely long label drop
      to its own line rather than clipping. The emphasis row (`balance
      due`) keeps its existing weight/size treatment untouched. */
.ds-doc table.ds-doc-lines th.ds-doc-lines__note,
.ds-doc table.ds-doc-lines td.ds-doc-lines__note {
  white-space: normal;
  overflow-wrap: anywhere;
  min-inline-size: 8ch;
  max-inline-size: 220px;
}

.ds-doc .ds-doc-totals--compact {
  max-inline-size: 460px;
}

/* === qa-round2 === */
/* QA round-2 F4: the change-log diff table shared by every `.ds-doc`
   sibling (sale/purchase/purchase-return/sell-return/stock-transfer/
   stock-adjustment "Activities" column -- rendered by
   sale_pos/partials/activity_row.blade.php, `<table class="no-border
   table table-slim mb-0">`) measured at ~1.25:1 in dark mode. Root
   cause: `vendor.css` ships `.table th { background-color:#fff
   !important }` -- a base AdminLTE rule with NO theme awareness -- and
   nothing in this codebase had ever targeted `table.table-slim` inside
   `.ds-doc` before, so that `!important` white th background won
   outright regardless of theme, while the th's INK still inherited
   `.ds-doc`'s dark-mode `--ds-ink-1` (a colour meant for a dark
   surface). The two together are what measured 1.25:1: light ink on a
   colour meant to be dark, forced white by `!important`.
   `.ds-doc table.table-slim > tbody > tr > th/td` has specificity
   (0,3,2) -- `html[data-ui-theme="dark"]` attribute + `.ds-doc` class +
   `table-slim` class + `table`/`th` types -- well above `.table th`'s
   (0,1,1), so an `!important` here reliably wins regardless of source
   order. Both themes get an EXPLICIT surface + ink pair from this
   file's own existing tokens (same `--ui-surface-1`/`--ds-ink-1`
   already used for the sibling `.ds-doc-lines` header/footer bands a
   few rules up) rather than leaving light mode to the accidental
   correctness of the vendor default -- light-mode measured 14.72:1,
   dark-mode 12.05:1 (both far past 4.5:1). A `<span class="label
   bg-info">` VALUE cell keeps its own self-contained background/ink
   pairing (untouched, already legible in both themes) -- only the
   plain `th` label cells and any plain-text `td` (the free-text
   `update_note` row) are affected. */
.ds-doc table.table-slim > tbody > tr > th,
.ds-doc table.table-slim > tbody > tr > td {
  background: var(--ui-surface-1, #f5f8ff) !important;
  color: var(--ds-ink-1, #0f172a) !important;
}

html[data-ui-theme="dark"] .ds-doc table.table-slim > tbody > tr > th,
html[data-ui-theme="dark"] .ds-doc table.table-slim > tbody > tr > td {
  background: var(--ui-surface-1, #1d2e4d) !important;
  color: var(--ds-ink-1, #e2e8f0) !important;
}
