/* ==========================================================================
   TrackFlo tables: DataTables theming and cell flags.
   Reads tokens from tf-tokens.css only — no hex literals.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Cell flags. These replace the jQuery
     $(row).find('td:eq(0)').css('background', '#D2222D').css('color', 'white')
   calls in the table_versions renderers. An inline style beats every stylesheet,
   so a themeable board REQUIRES these be classes.

   Foreground is set explicitly (not currentColor) because the flag backgrounds
   change per theme and the text has to stay readable on both. Warn uses ink text:
   white on amber never clears contrast in either theme.
   -------------------------------------------------------------------------- */
.tf-cell--ok      { background: var(--tf-ok)      !important; color: var(--bs-secondary-bg) !important; }
.tf-cell--warn    { background: var(--tf-warn)    !important; color: var(--tf-ink)          !important; }
.tf-cell--danger  { background: var(--tf-danger)  !important; color: var(--bs-secondary-bg) !important; }
.tf-cell--neutral { background: var(--tf-neutral) !important; color: var(--bs-secondary-bg) !important; }
/* Brand-ink cell: the customer-view status column, dark on every row by design.
   Not a status flag — deliberately constant across themes. */
.tf-cell--ink     { background: var(--tf-ink)     !important; color: var(--bs-secondary-bg) !important; }

/* --------------------------------------------------------------------------
   DataTables chrome
   -------------------------------------------------------------------------- */
table.dataTable tbody td,
table.dataTable th {
  vertical-align: middle;
  text-align: left;
}

/* --------------------------------------------------------------------------
   Table polish (8.10.26): quiet header band, hairline row separators, hover
   highlight, roomier cells. Tokens only, so it reads correctly in all themes.
   -------------------------------------------------------------------------- */
/* No white-space: nowrap here (removed 8.11.26). A non-wrapping header makes the
   whole header PHRASE the column's minimum width, so "Next Appointment (your
   timezone)" claimed ~30ch in a column whose data needs 16. Letting headers wrap
   drops that floor to the longest single word. See the column-width block below. */
table.dataTable thead th {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--bs-secondary-color);
  background-color: var(--bs-secondary-bg);
  border-bottom: 2px solid var(--bs-border-color);
}
table.dataTable tbody td {
  padding: .6rem .75rem;
  border-bottom: 1px solid var(--bs-border-color);
  background-color: var(--bs-secondary-bg);
}
/* Hover highlight; tf-cell--* flags keep their color (they set background with
   !important, which deliberately outranks this). */
table.dataTable tbody tr:hover td {
  background-color: var(--bs-tertiary-bg);
}

/* Long values wrap rather than forcing a horizontal scroll.
   (.dt-container is DataTables 2's wrapper class; .dataTables_wrapper was 1.x.)

   overflow-wrap, NOT word-break (changed 8.11.26). `word-break: break-word` is a
   deprecated alias that behaves like `overflow-wrap: anywhere`: it drops the cell's
   min-content width to ONE CHARACTER. Every column then claims it can be 1ch wide,
   so nothing has a real floor and the header labels win all width arbitration —
   which is why "Urbana, IL" used to break across two lines while the appointment
   column sat half empty. `overflow-wrap: break-word` keeps min-content at the
   longest word and breaks one only when it would otherwise overflow. */
.dt-container .dataTable tbody td {
  white-space: normal;
  overflow-wrap: break-word;
}

/* Free-text comment cells (Latest Update). Same fix as above: was
   `word-break: break-all`, which mid-word-broke every value and so volunteered this
   column — the one that needs the MOST room — as the first to be squeezed.
   The old `max-width: 600px` is gone: auto table layout treats max-width on a cell
   as a suggestion and DataTables' measurement pass ignores it outright, so it never
   did anything. .tf-col--wide below carries the sizing intent instead. */
/* `anywhere`, not `break-word` (changed 8.20.26). The two break identically once a
   line is being laid out; they differ in what they contribute to MIN-CONTENT, which is
   the number `table-layout: auto` is obliged to satisfy. `break-word` leaves min-content
   at the longest single token, so one 390-char URL in a load update ("Added Tracking URL:
   https://us-east-2.protection.sophos.com?d=...", a Sophos-wrapped Samsara link) made this
   column's floor 390ch: measured 2217px inside a 1200px container, table 2951px wide, and
   every column to its right clipped out of view — reported as "we are missing columns".
   `anywhere` contributes 1ch instead, so no single token can set the floor.
   Do NOT promote this to the generic `.dt-container .dataTable tbody td` rule — that is
   the 8.11.26 bug.

   `min-width` is the floor `anywhere` takes away (9.22.26). The 8.20.26 note here said
   collapsing min-content was safe because .tf-col--wide's `width: 20%` "is a real
   allocation the column takes regardless". It is not. Under `table-layout: auto` a
   percentage is only honoured out of width left over AFTER every column has its
   min-content; once the other columns' min-content fills the container there is no
   leftover, and a column whose own min-content is 1ch gets 1ch. DataTables' autoWidth
   then measures that on its hidden clone and writes it into <colgroup> as px, so
   `columns.adjust()` just re-measures the same squeeze. Measured on the All Active Loads
   board with MacroPoint + two user-enabled columns at a 1440px viewport: Latest Update
   42px wide, text one or two letters per line, rows 1,821px tall — the board read as
   empty. At 1920 the same board was fine (403px), so it only bit laptop widths.

   A fixed-length min-width on a cell IS part of its min-content in Chrome, Firefox and
   Safari, so the column now stops at 15rem and the table scrolls sideways inside its
   .table-responsive wrapper instead (the long-URL case stays fixed: the token breaks
   inside those 15rem rather than setting a 390ch floor). On the class, not on
   .tf-col--wide, because the detention, dwell and customer boards use this class ALONE —
   the "only ever paired with .tf-col--wide" claim was never true of them either.
   Pinned by workflows/testing/test_board_comment_column_width_floor.py. */
.datatable-wrap-text {
  overflow-wrap: anywhere !important;
  white-space: normal !important;
  min-width: 15rem;
}

/* --------------------------------------------------------------------------
   Column width intent (8.11.26). Applied via DataTables `columns.className`,
   which lands on both the <th> (dt.js:4092) and every <td> (dt.js:3172).

   These use `width`, not `max-width`, deliberately. Under `table-layout: auto`
   max-width on a cell is advisory and browsers apply it inconsistently; `width`
   is a real input to the layout algorithm. An unsatisfiable `width: 1%` is the
   standard shrink-to-content idiom — the column collapses to its content and the
   remaining space goes to the columns that asked for more.

   This also survives DataTables' own sizing pass: with autoWidth on (the default,
   and the boards don't disable it) DT measures a hidden worst-case clone and copies
   the result onto the real header. It only writes an inline width there when
   `columns.width` is set explicitly — which the boards deliberately do NOT set — so
   these class widths reach both the clone and the live table.
   -------------------------------------------------------------------------- */

/* Bounded, short content — icons, badges, dropdowns, formatted timestamps.
   nowrap keeps each line intact so a date never breaks mid-value. */
.tf-col--fit  { width: 1%; white-space: nowrap; }
/* The nowrap above never reached a body cell until 9.25.26: the generic
   `.dt-container .dataTable tbody td { white-space: normal }` rule near the top of this file
   outranks a lone class selector, so it only ever applied to the <th>. Next Appt broke after
   the hyphen in "8:00-13:30" (VP Logistics feedback). Every --fit column is a timestamp, a
   number or icons, which is exactly what this class was meant to keep on one line. Pinned by
   workflows/testing/test_board_fit_columns_do_not_wrap.py. */
.dt-container .dataTable tbody td.tf-col--fit { white-space: nowrap; }

/* Short but unbounded content — reference numbers, assignee names, city/state.
   Shrinks like --fit, but an outlier (a long email, a long city) wraps at a word
   boundary instead of widening the column for every other row. */
.tf-col--snug { width: 1%; }

/* Middle tier — a bounded label set that needs more than its longest word but nowhere
   near a free-text column. The 22 issue labels run 9-32 chars with a longest single word
   of 12 ("Pre-Delivery"), so --snug would pin the column at 12ch and wrap "Pickup
   Detention Risk" onto three lines, while --wide gave it far more than it can use. */
.tf-col--mid { width: 8%; }

/* Free-text columns that should absorb the remaining space.
   NOTE (8.11.26): `width` here is a genuine allocation, not just a floor — a column
   carrying this takes its full share even when its content would fit in less. Issue was
   briefly on this class and rendered enormously wide as a result; it uses --mid now.
   Reserve --wide for columns whose content is actually unbounded. */
.tf-col--wide { width: 20%; }

/* DataTables 2 renamed the processing overlay: div.dt-processing. */
/* DT2 ships a generic four-dot spinner as the overlay's only child div; the app uses
   the branded truck loader (language.processing / loadingRecords), so the default
   spinner is hidden — the loader's <img>/<p> are not divs and are unaffected. */
div.dt-processing > div { display: none; }
/* Positioning is DataTables 2's own (absolute, centered in the table area) — the old
   bottom:100px override from 1.x pinned the truck near the footer. The panel matches
   the table surface with no border, so ONLY the animation reads (gate feedback
   8.10.26); the loader's "Delivering Results..." caption is hidden for the same
   reason. */
div.dt-processing {
  background: var(--bs-secondary-bg);
  border: 0;
  color: var(--bs-body-color);
  padding: .75rem 1.5rem;
}
div.dt-processing p { display: none; }

/* Skeleton rows for FIRST load (loadingRecords default in the imports partial):
   content-shaped placeholders, widths staggered so it reads as rows, not stripes. */
.tf-skeleton-rows {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: .5rem 0;
}
/* Row-height bars with alternating tint, so the placeholder reads like the striped
   table it becomes. */
.tf-skeleton-rows .tf-skeleton {
  width: 100%;
  height: 3.4rem;
  border-radius: 4px;
}
.tf-skeleton-rows .tf-skeleton:nth-child(2n) { opacity: .55; }
td.dt-empty:has(.tf-skeleton-rows) { padding: 0; }

/* Loading-state arbitration:
   - Skeletons visible (first load) -> suppress the truck overlay entirely.
   - True "No data available" + a refresh in flight -> hide the text, show the truck. */
div.dt-container:has(td.dt-empty .tf-skeleton-rows) div.dt-processing {
  display: none !important;
}
div.dt-container:has(div.dt-processing[style*="block"]) td.dt-empty:not(:has(.tf-skeleton-rows)) {
  visibility: hidden;
}

/* "No data available in table": centered in the table body instead of hugging the
   header row. */
table.dataTable td.dt-empty {
  text-align: center;
  vertical-align: middle;
  padding: 5rem 0;
  color: var(--bs-secondary-color);
}

/* Button row: discrete buttons, not a fused btn-group (gate feedback 8.10.26).
   Buttons-bs5 wraps the toolbar in .btn-group, which welds the buttons together;
   the gap spaces them and the radius restores each button's own corners. */
div.dt-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}
div.dt-buttons > .btn {
  border-radius: var(--tf-radius-sm) !important;
}

/* DataTables Buttons (refresh/filter/export). Generated at runtime.
   Ink-on-light in light/classic themes (today's look). Buttons 3's Bootstrap-5
   renderer emits .dt-buttons > .btn (no .dt-button class), so both shapes are
   covered. */
.dt-button,
.dt-button:hover, .dt-button:focus, .dt-button:active, .dt-button.active,
.dt-buttons .btn,
.dt-buttons .btn:hover, .dt-buttons .btn:focus, .dt-buttons .btn:active,
.buttons-columnVisibility {
  background-color: var(--tf-ink) !important;
  color: var(--tf-on-ink) !important;
  border: 4px solid transparent;
}

/* In full dark, ink-on-near-black is invisible (gate review round 2, 8.10.26):
   raise the buttons to the card surface with a hairline ring. */
[data-bs-theme="dark"] .dt-button,
[data-bs-theme="dark"] .dt-button:hover,
[data-bs-theme="dark"] .dt-button:focus,
[data-bs-theme="dark"] .dt-button:active,
[data-bs-theme="dark"] .dt-button.active,
[data-bs-theme="dark"] .dt-buttons .btn,
[data-bs-theme="dark"] .dt-buttons .btn:hover,
[data-bs-theme="dark"] .dt-buttons .btn:focus,
[data-bs-theme="dark"] .dt-buttons .btn:active,
[data-bs-theme="dark"] .buttons-columnVisibility {
  background-color: var(--bs-secondary-bg) !important;
  color: var(--bs-body-color) !important;
  box-shadow: 0 0 0 1px var(--bs-border-color);
}

/* The Columns (colvis) dropdown (9.12.26). Buttons renders each entry as
   <li class="dt-button buttons-columnVisibility"><a class="dropdown-item">label</a></li>,
   so the toolbar rules above painted every <li> ink while the label sat in the <a>,
   whose Bootstrap colour is the body colour -- ink on ink in light/classic (dark mode
   only worked because its body colour is light). Inside the collection, step aside
   and let Bootstrap's .dropdown-menu / .dropdown-item theme the entries; the ✓ on
   .dt-button-active is color: inherit, so it follows the menu colour too. */
div.dt-button-collection .dt-button,
div.dt-button-collection .dt-button:hover,
div.dt-button-collection .dt-button:focus,
div.dt-button-collection .dt-button:active,
div.dt-button-collection .dt-button.active,
div.dt-button-collection .buttons-columnVisibility {
  background-color: transparent !important;
  color: inherit !important;
  border: 0;
  box-shadow: none;
}

/* Long labels draw through the checkmark in the two-column Columns popover (screenshot
   9.13.26 -- "Load #, Consignee Ref #"). Root cause: Bootstrap's .dropdown-item is
   `white-space: nowrap` by default, and the library's own fixed two-column layout gives
   each entry only ~200px (400px total / 2 columns) with 3em reserved on the right for the
   ✓ -- any label whose text alone is close to that width overflows past the reservation
   instead of wrapping, landing under the checkmark. Wrapping is the durable fix (holds for
   any future label, not just today's longest one); widening the popover just makes wrapping
   less frequent for the labels we have today. margin-left must stay at -width/2 -- that's
   how the library centers a `fixed` collection -- so it's overridden alongside width. */
div.dt-button-collection.two-column .dropdown-item {
  white-space: normal;
}
div.dt-button-collection.fixed.two-column {
  width: 480px;
  margin-left: -240px;
}

/* Pagination. Generated at runtime by DataTables, so it must be themed even though
   no template references .page-link. */
.page-link {
  background: var(--bs-secondary-bg);
  color: var(--bs-body-color);
  border-color: var(--bs-border-color);
}
.page-link:hover { background: var(--bs-tertiary-bg); }
.active > .page-link {
  background: var(--tf-ink);
  border-color: var(--tf-ink);
  color: var(--tf-on-ink);
}

/* --------------------------------------------------------------------------
   Row-update flash (8.10.26): TrackfloRefresh adds .tf-row-flash after swapping
   a row's data, so the changed row announces itself and then settles.
   -------------------------------------------------------------------------- */
@keyframes tf-row-flash {
  0%   { box-shadow: inset 0 0 0 999px color-mix(in srgb, var(--tf-blue) 18%, transparent); }
  100% { box-shadow: inset 0 0 0 999px transparent; }
}
tr.tf-row-flash > td { animation: tf-row-flash 1.6s ease-out both; }

@media (prefers-reduced-motion: reduce) {
  tr.tf-row-flash > td { animation: none; }
}
