/* ════════════════════════════════════════════════════════════════════════════════════════════════
   THE VIOLATIONS TAB: GROUPS, THEIR INSPECTIONS, AND THE MAP (2026-10-14) — js/modules/violations-board.js
   ════════════════════════════════════════════════════════════════════════════════════════════════
   ONE FAMILY WITH PREDICTIVE'S LIST. The measures, the toolbar, the chips, the count line and the
   sort buttons wear the predictive list's classes as they are (report-detail.css: .pred-basics-table,
   .pred-vt-*, .pred-viol-table), so a change there changes both. What is here is what that list does
   not have: a row that opens, the inspections inside it, the map buttons and the map's dialog —
   and FMCSA's investigation results above the list (2026-10-14).

   Loaded after dark-mode.css (api-tool.html), so its body.theme-dark rules are with each part. Two
   of dark mode's blankets meet these tables: every table cell is striped and painted (!important),
   which an open row and its inspections must not be, and every class holding "-popup" is painted a
   flat box — Leaflet's popup and its tip included. Both are answered at #pageContent / .vb-mapbox
   strength below.

   WHAT FITS IS DECIDED BY THE CARD'S ROOM, NOT THE WINDOW: the page's gutters grow with the window,
   so the table's box is a size container (vbbox) and the narrower layouts follow its width. Phones
   (≤640px) are at the end of each part, not in mobile.css. */

.vb [hidden] { display: none !important; }
.vb-state { margin: 0; font-size: var(--fs-base); color: var(--text-soft, #566274); }
.vb-muted { color: var(--text-soft, #566274); }
/* A second line in a cell — a plate, the inspection site. Small, and never the figure. */
.vb-sub { display: block; font-size: var(--fs-xs); color: var(--text-soft, #566274); }

/* ── The grouped table ─────────────────────────────────────────────────────────────────────── */
.vb-scroll { container: vbbox / inline-size; }
table.vb-groups td.vb-c-name { min-width: 15rem; white-space: normal; }
table.vb-groups td.vb-c-basic { white-space: nowrap; }
table.vb-groups th.vb-num, table.vb-groups td.vb-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
table.vb-groups th.vb-c-date, table.vb-groups td.vb-c-date { white-space: nowrap; font-variant-numeric: tabular-nums; }
table.vb-groups th.vb-c-map, table.vb-groups td.vb-c-map { width: 1%; text-align: right; white-space: nowrap; }
table.vb-groups td.vb-count { font-weight: 700; color: var(--text, #0f172a); }
table.vb-groups tr.vb-grp { cursor: pointer; }
/* Inline, not inline-block: a BASIC on two lines keeps its first on the row's line. */
.vb-basic { white-space: nowrap; }
.vb-basic + .vb-basic { margin-left: 0.6rem; }

/* THE ROW IS A DISCLOSURE: its name is the button (Enter and Space), with a caret that turns. */
.vb-toggle {
    appearance: none; border: 0; background: none; margin: 0 0 0 -0.2rem; padding: 0.05rem 0.2rem;
    display: inline-flex; align-items: flex-start; gap: 0.45rem; border-radius: 4px;
    font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.vb-caret {
    flex: 0 0 auto; width: 0; height: 0; margin-top: 0.42em;
    border-left: 5px solid currentColor; border-top: 4px solid transparent; border-bottom: 4px solid transparent;
    transition: transform var(--dur-fast, 120ms) ease;
}
.vb-toggle[aria-expanded="true"] .vb-caret { transform: rotate(90deg); }
/* anywhere, not break-word: a long unbroken token (a code run together, a pasted string) must not
   set the column's floor. */
.vb-name { font-weight: 600; color: var(--text, #0f172a); overflow-wrap: anywhere; }
.vb-toggle:hover .vb-name { text-decoration: underline; text-underline-offset: 3px; }
/* Its codes under it, lined up with the name rather than the caret. */
.vb-codes {
    display: block; margin: 0.12rem 0 0 1.05rem; font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
    color: var(--text-soft, #566274);
}

/* The map buttons: the predictive toolbar's quiet button, with a pin. */
.vb-mapbtn {
    appearance: none; display: inline-flex; align-items: center; gap: 0.35rem; height: 2rem; padding: 0 0.6rem;
    font: inherit; font-size: var(--fs-sm); font-weight: 600; line-height: 1; white-space: nowrap;
    color: var(--accent-ink, #1d4ed8); background: var(--surface-alt, #fff);
    border: 1px solid var(--border, #dbe1ea); border-radius: var(--radius-xs, 6px); cursor: pointer;
}
.vb-mapbtn:hover { border-color: var(--accent, #2563eb); }
.vb-mapbtn-sm { height: 1.75rem; padding: 0 0.45rem; }
.vb-pin-ico { flex: 0 0 auto; }
.vb-map-short { display: none; }

/* An open row and what it opens read as one block: the same tint, an accent line down the side. */
#pageContent table.vb-groups > tbody > tr.vb-grp.is-open > td { background: var(--surface, #f4f6fa); }
#pageContent table.vb-groups > tbody > tr.vb-detail:hover { background: transparent; }
#pageContent table.vb-groups > tbody > tr.vb-detail > td.vb-detail-cell {
    padding: 0.05rem 0.6rem 0.85rem 1.55rem; background: var(--surface, #f4f6fa); cursor: default;
}
/* THE OPEN ROW'S INSPECTIONS TAKE THE BOX'S WIDTH, NOT THE TABLE'S: they never widen the groups
   table through the cell they span, and when that table is wider than its box they stay in view
   (sticky) while it scrolls under them. If they need more than the box has, they scroll in here. */
.vb-detail-wrap {
    position: sticky; left: 1.55rem; width: calc(100cqw - 2.15rem); box-sizing: border-box; overflow-x: auto;
    padding-left: 0.85rem; box-shadow: inset 3px 0 0 var(--accent-soft-border, #c7d9fb);
}

/* ── An open row's inspections ─────────────────────────────────────────────────────────────── */
/* One <tbody> per inspection: its date, report and place span its rows, a row per violation. */
table.vb-insp { width: 100%; }
#pageContent table.vb-insp th { position: static; background: transparent; white-space: nowrap; }
#pageContent table.vb-insp > tbody > tr > td { vertical-align: top; border-bottom: 0; }
#pageContent table.vb-insp > tbody + tbody > tr:first-child > td { border-top: 1px solid var(--border, #dbe1ea); }
#pageContent table.vb-insp > tbody > tr + tr > td { border-top: 1px dashed var(--border, #dbe1ea); }
#pageContent table.vb-insp > tbody > tr:hover { background: transparent; }
#pageContent table.vb-insp > tbody:hover > tr > td { background: var(--accent-soft, #eff4ff); }
table.vb-insp th.vb-num, table.vb-insp td.vb-num { text-align: right; font-variant-numeric: tabular-nums; }
table.vb-insp td.vb-i-date, table.vb-insp td.vb-i-report,
table.vb-insp td.vb-i-code, table.vb-insp td.vb-i-tw { white-space: nowrap; }
table.vb-insp td.vb-i-date { font-variant-numeric: tabular-nums; }
table.vb-insp td.vb-i-code { font-weight: 600; }
/* THE WHOLE DESCRIPTION, ALWAYS: it wraps, between words, and its column takes the slack. */
table.vb-insp td.vb-i-desc { min-width: 14rem; white-space: normal; overflow-wrap: break-word; }
table.vb-insp td.vb-i-loc { min-width: 9rem; max-width: 18rem; white-space: normal; overflow-wrap: break-word; }
table.vb-insp td.vb-i-veh { min-width: 6rem; }
table.vb-insp th.vb-i-map, table.vb-insp td.vb-i-map { width: 1%; text-align: right; white-space: nowrap; }
table.vb-insp .pred-insp-report-link { font-size: inherit; color: var(--accent-ink, #1d4ed8); }
/* The report's state beside its number, as the predictive list writes it (2026-10-15). */
.vb-i-st { color: var(--text-muted, #475569); }
/* NOTHING TO MAP, NO MAP COLUMN (2026-10-15): no row in the table has an address (only states), and
   the locations have answered. While they are on their way the column keeps its place. */
table.vb-groups.vb-nomap > thead > tr > th.vb-c-map, table.vb-groups.vb-nomap > tbody > tr > td.vb-c-map,
table.vb-insp.vb-nomap > thead > tr > th.vb-i-map, table.vb-insp.vb-nomap > tbody > tr > td.vb-i-map { display: none !important; }

/* Every control shows where the keyboard is. */
.vb-toggle:focus-visible, .vb-mapbtn:focus-visible, table.vb-insp .vb-report:focus-visible,
.vb-mapclose:focus-visible, .vb-mapbox .leaflet-container a:focus-visible {
    outline: var(--focus-outline, 2px solid #2563eb); outline-offset: 2px;
}

/* Dark mode: no stripes or painted cells under these rows (dark-mode.css paints every table cell),
   the open block a step darker than the card, the hover a faint blue. */
body.theme-dark #pageContent table.vb-groups > tbody > tr > td,
body.theme-dark #pageContent table.vb-insp > tbody > tr > td { background-color: transparent !important; }
body.theme-dark #pageContent table.vb-groups > tbody > tr:hover,
body.theme-dark #pageContent table.vb-insp > tbody > tr:hover { background: transparent !important; }
body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-grp:hover > td,
body.theme-dark #pageContent table.vb-insp > tbody:hover > tr > td { background-color: rgba(122, 169, 247, 0.08) !important; }
body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-grp.is-open > td,
body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-detail > td.vb-detail-cell { background-color: var(--surface, #202023) !important; }
body.theme-dark #pageContent table.vb-insp thead th { background: transparent !important; }
body.theme-dark .vb-detail-wrap { box-shadow: inset 3px 0 0 var(--accent-soft-border, #2f4a76); }
body.theme-dark .vb-mapbtn { border-color: var(--border-strong, #565663); }

/* ── Less room than a wide screen's (the box under 1080px, a phone aside) ───────────────────── */
/* The headings, a group's name and BASIC and an inspection's road may take two lines, the
   descriptions give up some of their floor and "View on map" says "Map": the groups fit from about
   a 1000px window. Narrower still, the table scrolls in its box with Map pinned to the right edge —
   as Predictive pins Remove — and the page itself never does. */
@media (min-width: 641px) {
    @container vbbox (max-width: 1080px) {
        table.vb-groups th, table.vb-groups th.vb-num, table.vb-groups th.vb-c-date { white-space: normal; }
        table.vb-groups td.vb-c-name { min-width: 8rem; }
        table.vb-groups td.vb-c-basic, table.vb-groups td.vb-c-basic .vb-basic { white-space: normal; }
        .vb-groups .vb-map-long { display: none; }
        .vb-groups .vb-map-short { display: inline; }
        #pageContent table.vb-insp th { white-space: normal; }
        table.vb-insp td.vb-i-desc { min-width: 9rem; }
        table.vb-insp td.vb-i-loc { min-width: 7rem; max-width: none; }
        table.vb-groups th.vb-c-map, table.vb-groups td.vb-c-map { position: sticky; right: 0; box-shadow: inset 1px 0 0 var(--border, #dbe1ea); }
        table.vb-groups th.vb-c-map { z-index: 2; }
        #pageContent table.vb-groups > tbody > tr.vb-grp > td.vb-c-map { z-index: 1; background: var(--surface-alt, #fff); }
        #pageContent table.vb-groups > tbody > tr.vb-grp:hover > td.vb-c-map { background: var(--accent-soft, #eff4ff); }
        #pageContent table.vb-groups > tbody > tr.vb-grp.is-open > td.vb-c-map { background: var(--surface, #f4f6fa); }
        body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-grp > td.vb-c-map { background-color: var(--surface-alt, #26262a) !important; box-shadow: inset 1px 0 0 var(--border-strong, #565663); }
        body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-grp:hover > td.vb-c-map { background-color: #2c3039 !important; }
        body.theme-dark #pageContent table.vb-groups > tbody > tr.vb-grp.is-open > td.vb-c-map { background-color: var(--surface, #202023) !important; }
    }
    /* A TABLET, UPRIGHT (the box under about 880px, 2026-10-14): the table no longer fit, and the
       pinned Map column covered "Most recent" — the order the list is in — at 820px and hid it at
       768. The BASIC goes under the group's name instead of in a column of its own. */
    @container vbbox (max-width: 880px) {
        table.vb-groups .vb-c-basic { display: none; }
        table.vb-groups td.vb-c-name { min-width: 7rem; }
        table.vb-groups .vb-basic-sub { display: block; }
    }
}
.vb-basic-sub { display: none; margin: 0.12rem 0 0 1.05rem; font-size: var(--fs-xs); color: var(--text-soft, #566274); }
.vb-basic-sub .vb-basic { white-space: normal; }

/* FMCSA'S SUMMARY ALONE (no inspection rows came with the report, 2026-10-14): a row per code or
   group with its count, severity and OOS, and nothing behind it to open, date or map. */
table.vb-groups.vb-summary > thead > tr > th.vb-c-insp, table.vb-groups.vb-summary > tbody > tr > td.vb-c-insp,
table.vb-groups.vb-summary > thead > tr > th.vb-c-date, table.vb-groups.vb-summary > tbody > tr > td.vb-c-date,
table.vb-groups.vb-summary > thead > tr > th.vb-c-map, table.vb-groups.vb-summary > tbody > tr > td.vb-c-map { display: none !important; }
table.vb-groups.vb-summary tr.vb-grp { cursor: default; }
table.vb-groups.vb-summary .vb-codes, table.vb-groups.vb-summary .vb-basic-sub { margin-left: 0; }

/* AN INSPECTION AS A CARD, when its ten columns no longer fit the box (under 950px, a phone
   included): the date and the map button on top, the report, the state and time weight, the
   vehicle and the place, and each violation — code and severity, its description under them.
   Cards sit side by side where there is room. (Its own layout: mobile-tables.js leaves a
   [data-no-reflow] table alone, and its row spans would not survive the generic phone cards.) */
@container vbbox (max-width: 949px) {
    table.vb-insp { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: 8px; width: 100%; }
    table.vb-insp > thead { display: none; }
    table.vb-insp > tbody.vb-insp-group {
        display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: row dense; align-content: start; gap: 6px 12px;
        padding: 10px 12px; border: 1px solid var(--border, #dbe1ea); border-radius: 10px; background: var(--surface-alt, #fff);
    }
    table.vb-insp > tbody > tr { display: contents; }
    #pageContent table.vb-insp > tbody > tr > td {
        display: block; min-width: 0; max-width: none; padding: 0; border: 0; background: transparent;
        text-align: left; white-space: normal; overflow-wrap: break-word;
    }
    #pageContent table.vb-insp > tbody:hover > tr > td { background: transparent; }
    /* The desktop's lines between inspections and between violations outrank the reset above;
       a card draws its own (below). */
    #pageContent table.vb-insp > tbody + tbody > tr:first-child > td,
    #pageContent table.vb-insp > tbody > tr + tr > td { border-top: 0; }
    table.vb-insp > tbody > tr > td::before {
        content: attr(data-label); display: inline; margin-right: 0.4em;
        font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.02em; color: var(--text-muted, #475569);
    }
    table.vb-insp td.vb-i-date { order: -10; grid-column: 1; align-self: center; font-weight: 700; }
    table.vb-insp td.vb-i-map { order: -9; grid-column: 2; justify-self: end; width: auto; }
    table.vb-insp td.vb-i-report { order: -8; grid-column: 1 / -1; }
    /* A line of its own (2026-10-15): its partner was the State cell, now beside the report, and a
       half-row left free took the first violation's code out of its place beside its severity. */
    table.vb-insp td.vb-i-tw { order: -6; grid-column: 1 / -1; }
    table.vb-insp td.vb-i-veh { order: -5; grid-column: 1 / -1; }
    /* A report number is one thing: it never breaks across lines. */
    table.vb-insp td.vb-i-report a { white-space: nowrap; }
    #pageContent table.vb-insp td.vb-i-loc { order: -4; grid-column: 1 / -1; padding-bottom: 6px; border-bottom: 1px solid var(--border-subtle, #e8ecf3); }
    table.vb-insp td.vb-i-code { grid-column: 1; }
    table.vb-insp td.vb-i-sev { grid-column: 2; }
    table.vb-insp td.vb-i-desc { grid-column: 1 / -1; }
    #pageContent table.vb-insp > tbody > tr:not(:last-child) > td.vb-i-desc { padding-bottom: 6px; border-bottom: 1px dashed var(--border, #dbe1ea); }
    table.vb-insp td.vb-i-date::before, table.vb-insp td.vb-i-map::before, table.vb-insp td.vb-i-desc::before { display: none; }
    table.vb-insp .vb-sub { display: inline; margin-left: 0.35em; }
    table.vb-insp td.vb-i-loc .vb-sub::before { content: "· "; }
    body.theme-dark table.vb-insp > tbody.vb-insp-group { border-color: var(--border-strong, #565663); }
    /* A CARD IS ONE SURFACE (2026-10-14): the desktop's dark hover tint (above, !important) painted
       each of a hovered card's cells — a slab behind every value, and on a touch screen it stayed
       after the tap. No tint here, as in light mode. */
    body.theme-dark #pageContent table.vb-insp > tbody:hover > tr > td { background-color: transparent !important; }
}

/* ── Phones: cards ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
    /* mobile-tables.js makes each group a card (the name its title); the map button gets a line. */
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-map { grid-column: 1 / -1; text-align: left; }
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-map::before { display: none; }
    table.vb-groups[data-m-reflow] td.vb-c-name { min-width: 0; }
    /* THE NAME IS STILL THE CARD'S TITLE (2026-10-15): the row leads with the date now, in the
       predictive list's order, and mobile.css makes a card's first cell its title. */
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-name { order: -1; grid-column: 1 / -1; font-weight: 600; }
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-name::before { display: none; }
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-date { grid-column: auto; font-weight: 400; }
    table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td.vb-c-date::before { display: inline; }
    #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-grp.is-open { border-color: var(--accent-soft-border, #c7d9fb) !important; }
    #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-grp.is-open > td { background: transparent !important; }
    /* Under an open card, its inspections — one card each — hang off an accent line. mobile.css sets
       a card's first cell in 600; here that cell holds every inspection card. */
    #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-detail > td.vb-detail-cell {
        padding: 0 0 0 10px !important; background: transparent !important; font-weight: 400;
        box-shadow: inset 3px 0 0 var(--accent-soft-border, #c7d9fb);
    }
    .vb-detail-wrap { position: static; width: auto; overflow: visible; padding-left: 0; box-shadow: none; }
    body.theme-dark .vb-detail-wrap { box-shadow: none; }
    /* DARK, A CARD IS ONE SURFACE TOO (2026-10-14): the desktop's dark rules for an open, hovered
       or tapped row (above, !important, at #pageContent strength) out-ranked mobile.css's card
       reset and this block's own, and painted each value of the card — and the strip its
       inspections hang from — a slab of its own. */
    body.theme-dark #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-grp > td,
    body.theme-dark #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-grp:hover > td,
    body.theme-dark #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-grp.is-open > td,
    body.theme-dark #pageContent table.vb-groups[data-m-reflow] > tbody > tr.vb-detail > td.vb-detail-cell { background-color: transparent !important; }
}

/* ── Investigation results (2026-10-14) ───────────────────────────────────────────────────────── */
/* FMCSA's acute and critical findings from investigations, between the measures and the roadside
   list, in the same table family (.violations-table, .pred-viol-table for the sort arrows). What
   carries colour has a class of its own: dark mode flattens the background of any class holding
   "pred", and paints any holding "-results" — so no class here says either. */
.vb-inv {
    margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border-subtle, #e8ecf3);
    scroll-margin-top: calc(var(--measured-header-height, var(--app-header-height, 80px)) + 0.75rem);
}
/* Landed on from a BASIC's "Investigation" chip: a tint that fades, so the eye finds it. */
@keyframes vb-inv-arrive { from { background-color: var(--accent-soft, #eff4ff); } to { background-color: transparent; } }
.vb-inv.is-arrived { animation: vb-inv-arrive 1.4s ease-out; }
@media (prefers-reduced-motion: reduce) { .vb-inv.is-arrived { animation: none; } }
/* A sub-heading of the card: design-system.css sizes every #pageContent h3 for a page. The count
   reads as its second half; card-sources.js floats "Source: …" at its right end. */
#pageContent .vb-inv-title {
    margin: 0 0 0.5rem; font-size: var(--fs-base, 1rem); font-weight: 700; line-height: 1.4; letter-spacing: 0;
    color: var(--text, #0f172a); text-wrap: pretty;
}
.vb-inv-sum { font-weight: 400; color: var(--text-soft, #566274); }
/* A PHONE'S TITLE HAS NO ROOM FOR THE SOURCE (2026-10-14): card-sources.js then pins the line at
   the section's foot (is-foot, absolute), where it sat over the last line — "(Compliance Review)"
   at 390px with a two-digit count. The foot gets a line of its own, at the content's edge. */
.vb-inv.has-source-foot { padding-bottom: 1.35rem; }
.vb-inv > .card-source.is-foot { right: 0; }
/* Its lines are lists and labels, not prose: no 78ch measure (design-system.css #pageContent p),
   which broke "Most recent investigations" into three lines on a wide card. */
#pageContent .vb-inv p { max-width: none; }
.vb-inv-lede { margin: -0.3rem 0 0.55rem; font-size: var(--fs-sm); color: var(--text-soft, #566274); }
.vb-inv-scroll { overflow-x: auto; container: vbinv / inline-size; }
table.vb-inv-table td { vertical-align: baseline; }
table.vb-inv-table td.vb-inv-c-date, table.vb-inv-table td.vb-inv-c-code { white-space: nowrap; font-variant-numeric: tabular-nums; }
table.vb-inv-table td.vb-inv-c-basic, table.vb-inv-table td.vb-inv-c-kind { white-space: nowrap; }
/* THE INVESTIGATION MAY WRAP (2026-10-14, review): on one line, FMCSA's "Onsite Comprehensive
   Investigation" ran the table 42px past its card at 1024 and cut off the chip. Its floor (the
   cell is border-box, padding included) keeps "Compliance Review" and "Non-Ratable Review" on one
   line, with room for a wider system font than this machine's. */
table.vb-inv-table td.vb-inv-c-inv { white-space: normal; min-width: 10.75em; }
/* A wrapped heading lines up with its column (a <button> centres its lines), here and in the
   groups below. */
table.vb-inv-table .pred-vt-sort, table.vb-groups .pred-vt-sort { text-align: inherit; }
/* THE WHOLE DESCRIPTION: it wraps between words and its column takes the slack. anywhere, not
   break-word (2026-10-14, review), as .vb-name: a long unbroken token must not set its floor — one
   ran the rows 57px past the card at 660. */
table.vb-inv-table td.vb-inv-c-desc { width: 100%; min-width: 14rem; white-space: normal; overflow-wrap: anywhere; }
.vb-inv-code { font-weight: 600; color: var(--text, #0f172a); }
/* "×4": FMCSA lists the finding once per time it was cited, the way a group counts violations. */
.vb-inv-times { margin-left: 0.35rem; font-weight: 700; color: var(--text, #0f172a); }

/* Acute red, critical amber-red; one FMCSA left unsaid is outlined in the red. 13px, 5.6:1 and
   better on their fills. */
.vb-kind {
    display: inline-block; padding: 0 0.5rem; font-size: var(--fs-xs); font-weight: 700; line-height: 1.5;
    white-space: nowrap; border: 1px solid transparent; border-radius: var(--radius-pill, 999px);
}
.vb-kind-acute { color: #b91c1c; background: #fdecec; border-color: #f3b8b8; }
.vb-kind-critical { color: #9a3412; background: #fff1e6; border-color: #f5c9a8; }
.vb-kind-either { color: #b91c1c; background: transparent; border-color: #f3b8b8; }
/* The measures' chip beside a BASIC FMCSA marks "Acute/Critical Violations Discovered". */
.vb-inv-flag {
    appearance: none; margin: 0 0 0 0.45rem; padding: 0 0.45rem; vertical-align: baseline;
    font: inherit; font-size: var(--fs-xs); font-weight: 700; line-height: 1.5; white-space: nowrap;
    color: #b91c1c; background: #fdecec; border: 1px solid #f3b8b8; border-radius: var(--radius-pill, 999px); cursor: pointer;
}
/* UNDER THE NAME, ALWAYS, past a phone (2026-10-14, review): beside it, the chips of the longer
   names wrapped at laptop widths and the shorter did not — at 1366 two beside, two under, those
   lined up with neither the square nor the name. Here each starts where its name does (the
   indent .vb-codes uses); a phone's card keeps it beside the name. */
@media (min-width: 641px) {
    .vb-measures-table .vb-inv-flag { display: block; width: fit-content; margin: 0.15rem 0 0 1.05rem; }
}
.vb-inv-flag:hover { border-color: #b91c1c; }
.vb-inv-flag:focus-visible { outline: var(--focus-outline, 2px solid #2563eb); outline-offset: 2px; }

/* The quiet line, and the recent investigations under the rows (FMCSA's icon where it has one). */
.vb-inv-line, .vb-inv-recent { margin: 0; font-size: var(--fs-sm); line-height: 1.5; color: var(--text-soft, #566274); }
.vb-inv-scroll:not([hidden]) ~ .vb-inv-line, .vb-inv-recent { margin-top: 0.5rem; }
.vb-inv-mark { display: inline-flex; margin-left: 0.3rem; vertical-align: -2px; color: #b91c1c; }
@media (min-width: 641px) { .vb-inv-past { white-space: nowrap; } }

/* LESS ROOM (the card under ~860px, an upright tablet): at 820 the six columns ran 3px past the
   card and "Hours-of-Service" broke at its hyphens. The BASIC goes under the description, as the
   groups put it under the name, the headings may take two lines and the investigation gives up
   its floor. */
.vb-inv-basic-sub { display: none; margin-top: 0.15rem; font-size: var(--fs-xs); color: var(--text-soft, #566274); }
/* Its BASIC may wrap, as the groups' does: on one line it set the description's floor. */
.vb-inv-basic-sub .vb-basic { white-space: normal; }
@media (min-width: 641px) {
    @container vbinv (max-width: 860px) {
        table.vb-inv-table th { white-space: normal; }
        table.vb-inv-table td.vb-inv-c-inv { min-width: 0; }
        table.vb-inv-table .vb-inv-c-basic { display: none; }
        table.vb-inv-table .vb-inv-basic-sub { display: block; }
        table.vb-inv-table td.vb-inv-c-desc { min-width: 10rem; }
    }
    /* A window between a phone and ~700px (half a 1366 laptop): the rows ran up to 37px past the
       card and cut off their chips (2026-10-14, review). The description gives up more floor. */
    @container vbinv (max-width: 640px) {
        table.vb-inv-table td.vb-inv-c-desc { min-width: 7rem; }
    }
}

/* Dark mode: no stripes or painted cells (dark-mode.css paints every table cell, !important), a
   faint blue hover, and the chips in the dark palette's red and amber — all 5.4:1 and better. */
body.theme-dark .vb-inv { border-top-color: var(--border-subtle, #303036); }
body.theme-dark #pageContent table.vb-inv-table > tbody > tr > td { background-color: transparent !important; }
body.theme-dark #pageContent table.vb-inv-table > tbody > tr:hover { background: transparent !important; }
body.theme-dark #pageContent table.vb-inv-table > tbody > tr:hover > td { background-color: rgba(122, 169, 247, 0.08) !important; }
body.theme-dark .vb-kind-acute, body.theme-dark .vb-inv-flag { color: #fca5a5; background: rgba(239, 68, 68, 0.14); border-color: rgba(248, 113, 113, 0.45); }
body.theme-dark .vb-kind-critical { color: #fb923c; background: rgba(249, 115, 22, 0.14); border-color: rgba(251, 146, 60, 0.45); }
body.theme-dark .vb-kind-either { color: #fca5a5; background: transparent; border-color: rgba(248, 113, 113, 0.45); }
body.theme-dark .vb-inv-flag:hover { border-color: #fca5a5; }
body.theme-dark .vb-inv-mark { color: #f87171; }

/* A phone: mobile-tables.js makes each finding a card (six columns). The date and its chip head
   it; the investigation, the code and the BASIC each a line under their names; the description
   in full without one. Nothing in a card is a link, so it takes no hover tint either. */
@media (max-width: 640px) {
    table.vb-inv-table[data-m-reflow] > tbody > tr { grid-template-columns: minmax(0, 1fr) auto; }
    table.vb-inv-table[data-m-reflow] > tbody > tr > td { grid-column: 1 / -1; }
    table.vb-inv-table[data-m-reflow] > tbody > tr > td.vb-inv-c-date { grid-column: 1; grid-row: 1; align-self: center; }
    table.vb-inv-table[data-m-reflow] > tbody > tr > td.vb-inv-c-kind { grid-column: 2; grid-row: 1; justify-self: end; align-self: center; }
    table.vb-inv-table[data-m-reflow] > tbody > tr > td.vb-inv-c-kind::before,
    table.vb-inv-table[data-m-reflow] > tbody > tr > td.vb-inv-c-desc::before { display: none; }
    #pageContent table.vb-inv-table[data-m-reflow] > tbody > tr:hover { background: var(--surface-alt, #fff); }
    body.theme-dark #pageContent table.vb-inv-table[data-m-reflow] > tbody > tr,
    body.theme-dark #pageContent table.vb-inv-table[data-m-reflow] > tbody > tr:hover,
    body.theme-dark #pageContent table.vb-inv-table[data-m-reflow] > tbody > tr > td,
    body.theme-dark #pageContent table.vb-inv-table[data-m-reflow] > tbody > tr:hover > td { background-color: transparent !important; }
}

/* ── View on map: the dialog ──────────────────────────────────────────────────────────────────── */
/* Over the page and under the header, as the report dialog is (main.css .modal) — one step below
   it, so a report opened from a pin comes up over the map. */
.vb-mapmodal {
    position: fixed; inset: 0; z-index: 1990;
    display: flex; align-items: flex-start; justify-content: center;
    padding: calc(var(--measured-header-height, var(--app-header-height, 80px)) + 1rem) 1.5rem 1.5rem;
    background: rgba(15, 23, 42, 0.62); overflow-y: auto; overscroll-behavior: contain;
}
.vb-mapbox {
    position: relative; width: min(1000px, 100%); display: flex; flex-direction: column; gap: 0.65rem;
    padding: 1rem 1.25rem 1.1rem; color: var(--text-body, #1e293b); background: var(--surface-alt, #fff);
    border: 1px solid var(--border, #dbe1ea); border-radius: var(--radius-lg, 16px);
    box-shadow: 0 25px 80px rgba(15, 23, 42, 0.25);
}
.vb-maphead { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.vb-maptitles { min-width: 0; }
.vb-maptitle { margin: 0; font-size: var(--fs-lg); font-weight: 700; line-height: 1.3; color: var(--text, #0f172a); overflow-wrap: anywhere; }
.vb-mapsub { margin: 0.15rem 0 0; font-size: var(--fs-sm); color: var(--text-soft, #566274); overflow-wrap: anywhere; }
.vb-mapclose {
    appearance: none; flex: 0 0 auto; width: 40px; height: 40px; padding: 0; border-radius: 999px;
    font: inherit; font-size: 1.5rem; line-height: 1; color: var(--text-body, #1e293b);
    background: var(--surface, #f1f5f9); border: 1px solid var(--border, #dbe1ea); cursor: pointer;
}
.vb-mapclose:hover { border-color: var(--accent, #2563eb); }
.vb-mapcanvas {
    position: relative; height: min(60vh, 560px); min-height: 280px; overflow: hidden;
    border: 1px solid var(--border, #dbe1ea); border-radius: 12px; background: var(--surface, #f4f6fa);
}
.vb-mapmsg { margin: 0; padding: 1rem; font-size: var(--fs-sm); color: var(--text-soft, #566274); }
.vb-mapnotes { display: flex; flex-direction: column; gap: 0.2rem; }
.vb-mapnote { margin: 0; font-size: var(--fs-sm); line-height: 1.45; color: var(--text-soft, #566274); }
.vb-mapsource { margin: 0; font-size: var(--fs-xs); color: var(--text-soft, #566274); }

/* A pin's popup: the place, then each inspection there — date, report, road, its violations. */
.vb-mapbox .leaflet-container { font-family: inherit; }
.vb-mapbox .vb-mappop .leaflet-popup-content-wrapper { border-radius: 10px; }
.vb-mapbox .vb-mappop .leaflet-popup-content { margin: 12px 26px 12px 14px; font-size: var(--fs-sm); line-height: 1.4; color: var(--text-body, #1e293b); }
.vb-pop-place { margin-bottom: 0.35rem; font-weight: 700; color: var(--text, #0f172a); }
.vb-pop-list, .vb-pop-viols { list-style: none; margin: 0; padding: 0; }
.vb-pop-list { max-height: 240px; overflow-y: auto; }
.vb-pop-insp + .vb-pop-insp { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--border-subtle, #e8ecf3); }
.vb-pop-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.1rem 0.5rem; }
.vb-pop-date { font-weight: 600; font-variant-numeric: tabular-nums; }
.vb-mapbox .leaflet-container a.vb-pop-report { color: var(--accent-ink, #1d4ed8); font-weight: 600; }
.vb-pop-loc { font-size: var(--fs-xs); color: var(--text-muted, #475569); }
.vb-pop-viols { margin-top: 0.2rem; }
.vb-pop-viols li { margin: 0.1rem 0; }
.vb-pop-code { font-weight: 700; }
.vb-pop-sev { font-size: var(--fs-xs); white-space: nowrap; color: var(--text-soft, #566274); }

/* Dark mode. dark-mode.css paints every "-popup" class a flat #26262a (!important): the popup's
   own box and the tip's container must stay clear, or the rounded popup sits on a square and its
   tip on a bar. And its link colour (every <a>, !important) left the zoom buttons and the
   attribution light blue on white. */
body.theme-dark .vb-mapbox { border-color: var(--border-strong, #565663); box-shadow: 0 25px 80px rgba(0, 0, 0, 0.6); }
body.theme-dark .vb-mapclose { color: var(--text, #ececee); border-color: var(--border-strong, #565663); }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup,
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup-tip-container,
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup-content { background-color: transparent !important; }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup-content-wrapper,
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup-tip { background-color: #26262a !important; color: var(--text-body, #d4d4d8); box-shadow: 0 6px 22px rgba(0, 0, 0, 0.55); }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-popup-content { color: var(--text-body, #d4d4d8); }
body.theme-dark .vb-mapbox .vb-mapcanvas a.leaflet-popup-close-button { color: #d4d4d8 !important; background-color: transparent !important; }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-bar { border-color: #3f3f46; }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-bar a { background-color: #26262a !important; color: #e4e4e7 !important; border-bottom-color: #3f3f46 !important; }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-control-attribution { background: rgba(32, 32, 35, 0.9) !important; color: #d4d4d8 !important; }
body.theme-dark .vb-mapbox .vb-mapcanvas .leaflet-control-attribution a { color: #93c5fd !important; }
body.theme-dark .vb-pop-insp + .vb-pop-insp { border-top-color: #3f3f46; }

@media (max-width: 640px) {
    .vb-mapmodal { padding: calc(var(--measured-header-height, var(--app-header-height, 80px)) + 0.5rem) 0.5rem 0.5rem; }
    .vb-mapbox { padding: 0.75rem; border-radius: var(--radius-md, 12px); }
    .vb-mapcanvas { height: 55vh; min-height: 240px; }
}

/* ════════════════════════════════════════════════════════════════════════════════════════════════
   THE INSPECTIONS & CRASHES TABLES (2026-10-25) — js/modules/incidents-board.js
   ════════════════════════════════════════════════════════════════════════════════════════════════
   The owner: "Redesign the tables to look like the violations table", and a row's report "expand its
   details inline". Both tables ARE the board's groups table (.vb-groups, .vb-grp, .vb-toggle,
   .vb-detail, .pred-sorthead, .vb-scroll's container), so every rule above — the open row's tint,
   the detail's accent line, the narrower boxes, the phone's cards, dark mode — is theirs too. Here
   only what an inspection or a crash has that a violation group does not: the report and its
   state, the vehicle and the figures, the not-preventable chip, and the report a row opens onto. */
/* The count beside the title, in its line: card-sources.js floats the source to the line's right end.
   THE TITLE HOLDS ITS FLOAT (2026-10-26, review): on a phone the source has no room beside the title
   and drops under it, which a float does without making the title taller — card-sources.js, which
   foots a line that grows its title, saw nothing, and the line hung beside the description. */
.ib-section .analytics-tool-title { display: flow-root; }
.ib-section .analytics-tool-title > .incident-title-count { margin-left: 0.5rem; }
/* Said, not shown: the box's live region (incidents-board.js, say). */
.ib-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The phone's Sort (it has no header to click); the predictive bar's own select, full width. */
.ib > .ib-bar.pred-vt { display: none; margin: 0 0 0.5rem; padding: 0; border: 0; }
.ib .ib-meta { margin-top: 0; }
/* THE SORT ON A TABLET TOO (2026-10-25, review: four sorts could not be reached). Where the box hides
   the vehicle, a crash's plate, tow-away and release with their headings (below), the orders — and
   the one the list is in — are the select's, as on a phone. The box is a size container of its own
   for it (ibbox): the bar sits outside the table's (vbbox), at the same width. */
.ib { container: ibbox / inline-size; }
@media (min-width: 641px) {
    @container ibbox (max-width: 880px) {
        .ib > .ib-bar.pred-vt { display: block; }
        .ib > .ib-bar .pred-vt-sortsel { display: block; width: auto; max-width: 100%; }
    }
}
/* A report number is not a group's name: the board's 15rem floor would take a third of the row.
   ANYWHERE, THE WHOLE CELL (2026-10-26, review): a 35-character report number run together scrolled
   the table 8px at 641 — break-word, inherited, lowers no column's floor. */
table.vb-groups.ib-table td.vb-c-name { min-width: 10.5rem; overflow-wrap: anywhere; }
/* AN INSPECTION'S SEVERITY WEIGHT, BASIC BY BASIC (2026-10-26, review; incidents-board.js sevHtml):
   each BASIC the board's swatch and name with its capped figure, one to a line in the table — the
   highest on top, so the column reads down like the figures beside it — and run on with " · " in a
   phone's card. Each part is whole on its line; a clean inspection is the board's plain "—". */
table.ib-table td.ib-c-sevb { white-space: normal; }
table.ib-table td.ib-c-sevb .ib-sevb { display: block; white-space: nowrap; font-variant-numeric: tabular-nums; }
table.ib-table td.ib-c-sevb .ib-sevsep { display: none; }
table.ib-table td.ib-c-sevb .ib-unknown { cursor: help; }
/* WHO AND WHAT ON THE LEFT, THE FIGURES ON THE RIGHT (2026-10-25, review): on a wide box the report
   column took the spare width, each vehicle about 450px from its report. The report keeps room for a
   line of codes, the vehicle sits beside it, and the spare goes in front of the figures. */
@container vbbox (min-width: 1081px) {
    table.ib-table-insp th.vb-c-date, table.ib-table-insp th.ib-c-sev, table.ib-table-insp th.ib-c-tw { width: 1%; }
    table.ib-table-insp th.ib-c-report { width: 34%; }
    table.ib-table-insp th.ib-c-veh { width: 16%; }
}
/* anywhere, as .vb-name: a vehicle written as one long token must not set the column's floor. */
table.ib-table td.ib-c-veh { min-width: 7rem; white-space: normal; overflow-wrap: anywhere; }
table.ib-table td.ib-c-yn { white-space: nowrap; }
/* A PLATE KEEPS TO ITS LINE, AND ONE RUN TOGETHER WRAPS (2026-10-25, review: a 30-character plate,
   nowrap, pushed the crash table 114px past its card at 1024). The floor holds a real plate and its
   state whole; the space before the state does not break (plateText). */
table.ib-table td.ib-c-plate { min-width: 7rem; overflow-wrap: anywhere; }
/* Yes and no centred under their headings: left-aligned beside the right-aligned injuries, "2 Yes"
   read as one figure (2026-10-25, review). */
table.ib-table th.ib-c-yn, table.ib-table td.ib-c-yn { text-align: center; }
/* Show all, under the rows at their left, as Predictive's: the box is a flex column, which would
   stretch the button across it and centre its words. */
.ib > .ib-more { align-self: flex-start; }
/* FMCSA's text where a figure belongs, as it came: it may wrap — the cell does not (figHtml). */
table.ib-table .ib-raw { white-space: normal; overflow-wrap: anywhere; }
.ib-st { margin-left: 0.3rem; }
/* A code is one thing: "396.3(a)(1)" never breaks before its "(1)"; the line breaks between codes —
   and "+8 more" is one too. */
.ib-code { white-space: nowrap; }
/* The columns a tablet has no room for, under the report instead (as the board puts the BASIC). */
.ib-alt { display: none; margin: 0.12rem 0 0 1.05rem; font-size: var(--fs-xs); color: var(--text-soft, #566274); overflow-wrap: anywhere; }
/* A TABLET, UPRIGHT (the box under about 880px): the six inspection columns needed 736px of a 657px
   box at 768, the nine crash columns 878px. The vehicle goes under the report, and so do a crash's
   plate, tow-away and release; the figures keep their columns and their sorts. */
@media (min-width: 641px) {
    @container vbbox (max-width: 880px) {
        table.ib-table .ib-c-veh, table.ib-table .ib-c-plate, table.ib-table .ib-c-yn { display: none; }
        table.ib-table .ib-alt { display: block; }
        table.vb-groups.ib-table td.vb-c-name { min-width: 8rem; }
    }
}
.ib-hit { font-weight: 700; color: var(--text, #0f172a); }
/* A clean inspection says so under its number, quietly. */
.ib-clean { font-style: italic; }
/* FMCSA's ruling, a chip under the report: green, as the old table's badge was; 6.9:1 and better. */
.ib-np {
    display: inline-block; padding: 0 0.5rem; font-size: var(--fs-xs); font-weight: 700; line-height: 1.5; white-space: nowrap; font-style: normal;
    color: #166534; background: #dcfce7; border: 1px solid #a7e3bd; border-radius: var(--radius-pill, 999px);
}
/* Landed on from the map's state panel: under the header, and a tint that fades so the eye finds it.
   A shadow, not a background: dark mode paints these cells with !important, which no animation beats. */
table.ib-table > tbody > tr.vb-grp { scroll-margin-top: calc(var(--measured-header-height, var(--app-header-height, 80px)) + 0.75rem); }
@keyframes ib-arrive { from { box-shadow: inset 0 0 0 100vmax var(--accent-soft, #eff4ff); } to { box-shadow: inset 0 0 0 100vmax transparent; } }
#pageContent table.ib-table > tbody > tr.vb-grp.is-arrived > td { animation: ib-arrive 1.4s ease-out; }
@media (prefers-reduced-motion: reduce) { #pageContent table.ib-table > tbody > tr.vb-grp.is-arrived > td { animation: none; } }

/* ── An open row's report ──────────────────────────────────────────────────────────────────── */
/* Its lines are labels and facts, not prose: no 78ch measure (design-system.css #pageContent p). */
#pageContent .ib-detail p { max-width: none; }
.ib-line { margin: 0.35rem 0 0.55rem; font-size: var(--fs-sm); line-height: 1.5; color: var(--text-soft, #566274); }
.ib-line .ib-retry { padding: 0 0.15rem; }
.ib-spin {
    display: inline-block; width: 0.95em; height: 0.95em; margin-right: 0.5rem; vertical-align: -0.15em;
    border: 2px solid var(--border, #dbe1ea); border-top-color: var(--accent, #2563eb); border-radius: 50%;
    animation: ib-spin 0.8s linear infinite;
}
@keyframes ib-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ib-spin { animation: none; border-top-color: var(--border, #dbe1ea); } }
/* The facts in groups side by side, sharing the row (auto-fit: two groups take half each, not a
   quarter); the vehicles and violations the full width. */
.ib-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 0.85rem 1.5rem; padding: 0.4rem 0 0.35rem; }
.ib-group { min-width: 0; }
.ib-tables { display: grid; gap: 0.85rem; padding: 0.4rem 0 0.35rem; }
.ib-facts + .ib-tables { padding-top: 0.5rem; }
.ib-group-title {
    margin: 0 0 0.35rem; font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    color: var(--text-muted, #475569);
}
.ib-dl { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: 0.4rem 1rem; margin: 0; }
.ib-fact { min-width: 0; }
/* A VIN HAS A LINE OF ITS OWN AT EVERY WIDTH (2026-10-26, review): in a 136px column, at 1440, 1100
   and 768, it broke before its last character. */
.ib-dl > .ib-fact.ib-wide { grid-column: 1 / -1; }
.ib-fact dt { font-size: var(--fs-xs); font-weight: 600; color: var(--text-soft, #566274); }
/* anywhere: a VIN or an address run together must not set the column's floor. */
.ib-fact dd { margin: 0.05rem 0 0; font-size: var(--fs-sm); color: var(--text-body, #1e293b); overflow-wrap: anywhere; }
.ib-none { margin: 0; font-size: var(--fs-sm); color: var(--text-soft, #566274); }
.ib-sub-scroll { overflow-x: auto; }
/* Should a value still be too wide, Chrome stops the keyboard on the box that scrolls: ringed. */
.ib-sub-scroll:focus-visible { outline: var(--focus-outline, 2px solid #2563eb); outline-offset: 2px; }
#pageContent table.ib-sub th { position: static; background: transparent; }
/* ANYWHERE, NOT BREAK-WORD (2026-10-26, review): break-word lowers no column's floor, so a VIN or a
   plate run together, or a 90-character word, widened the record's tables past the record and sent
   SMS, BASIC and Reason behind a sideways scroll at 768 and from 900 to 1440. A code still keeps to
   its line (ib-whole). */
table.ib-sub td { vertical-align: top; white-space: normal; overflow-wrap: anywhere; }
table.ib-sub td.ib-whole { white-space: nowrap; }
/* …BUT A WORD STAYS WHOLE (2026-10-26, review): anywhere in every cell let a narrow column split its
   words, "Vehicl|e Maint." at 390 and "HOS Compli|ance" at 900–980. A column of short words keeps
   them whole (ib-words, incidents-board.js tableHtml), its longest word its floor; the long values
   above, and a token run together in any column, still break anywhere. */
table.ib-sub td.ib-words { overflow-wrap: break-word; }
#pageContent table.ib-sub > tbody > tr:hover { background: transparent; }
#pageContent table.ib-sub > tbody > tr:hover > td { background: var(--accent-soft, #eff4ff); }
.ib-fmcsa { margin: 0.55rem 0 0.1rem; font-size: var(--fs-sm); }
#pageContent .ib-fmcsa a { color: var(--accent-ink, #1d4ed8); font-weight: 600; }
.ib-retry:focus-visible, .ib-fmcsa a:focus-visible { outline: var(--focus-outline, 2px solid #2563eb); outline-offset: 2px; }
/* A RECORD NARROWER THAN ITS TABLES SHOWS THEIR ROWS AS CARDS (2026-10-26, review): from 641 to 800px
   (an iPad upright) the eight columns of an inspection's violations needed 641px of a 507–638px record
   and scrolled sideways, the last column cut mid-word — as the board cards its inspections under a
   950px box. The record is the size container; under 720px of it each row is a card, as a phone's
   (mobile.css draws those, ≤640px), each value under its column's name (data-label), two to a line,
   the first the card's title and the long ones (ib-wide) a line of their own; the cards side by side
   where there is room. */
.ib-detail { container: ibrec / inline-size; }
@media (min-width: 641px) {
    @container ibrec (max-width: 720px) {
        .ib-detail table.ib-sub { display: block; width: 100%; }
        .ib-detail table.ib-sub > thead { display: none; }
        .ib-detail table.ib-sub > tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 8px; }
        #pageContent .ib-detail table.ib-sub > tbody > tr {
            display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-content: start; gap: 6px 12px;
            padding: 10px 12px; border: 1px solid var(--border, #dbe1ea); border-radius: 10px; background: var(--surface-alt, #fff);
        }
        #pageContent .ib-detail table.ib-sub > tbody > tr > td {
            display: block; min-width: 0; padding: 0; border: 0; background: transparent; text-align: left; white-space: normal; overflow-wrap: anywhere;
        }
        /* A LABEL AND A ONE-WORD VALUE MAY PART (2026-10-26, review): drawn in front of its value with no
           space between, "Make" and "FREIGHTLINER" were one word to the line, and in half a card the
           make broke "FREIGHTLINE|R" (here at 700, on a phone at 360). A zero-width space after the
           label lets the value go under it whole. */
        .ib-detail table.ib-sub > tbody > tr > td::before {
            content: attr(data-label) "\200B"; margin-right: 0.4em; font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.02em; color: var(--text-muted, #475569);
        }
        #pageContent .ib-detail table.ib-sub > tbody > tr > td:first-child { grid-column: 1 / -1; font-weight: 600; }
        .ib-detail table.ib-sub > tbody > tr > td:first-child::before { display: none; }
        #pageContent .ib-detail table.ib-sub > tbody > tr > td.ib-wide { grid-column: 1 / -1; }
        #pageContent .ib-detail table.ib-sub > tbody > tr:hover > td { background: transparent; }
        body.theme-dark #pageContent .ib-detail table.ib-sub > tbody > tr { border-color: var(--border-strong, #565663); }
        body.theme-dark #pageContent .ib-detail table.ib-sub > tbody > tr:hover > td { background-color: transparent !important; }
    }
}

/* Dark mode: the chip in the dark palette's green (8.9:1), the count pill a step off the card, and
   no stripes or painted cells in the report's tables (dark-mode.css paints every table cell). */
body.theme-dark .ib-np { color: #86efac; background: rgba(34, 197, 94, 0.14); border-color: rgba(74, 222, 128, 0.42); }
body.theme-dark .ib-section .incident-title-count { color: #bfdbfe; background: rgba(96, 165, 250, 0.18); }
body.theme-dark .ib-spin { border-color: var(--border-strong, #565663); border-top-color: var(--accent, #7aa9f7); }
body.theme-dark #pageContent table.ib-sub > tbody > tr > td { background-color: transparent !important; }
body.theme-dark #pageContent table.ib-sub > tbody > tr:hover { background: transparent !important; }
body.theme-dark #pageContent table.ib-sub > tbody > tr:hover > td { background-color: rgba(122, 169, 247, 0.08) !important; }
body.theme-dark #pageContent table.ib-sub thead th { background: transparent !important; }
/* The map's state panel, dark (2026-10-25): its count pills kept the light palette's ink, 6
   inspections at 2.1:1 on the dark card (review; so before the rename too). The dark palette's. */
body.theme-dark .incident-state-panel .state-count-badge.inspection { color: #93c5fd; background: rgba(96, 165, 250, 0.16); }
body.theme-dark .incident-state-panel .state-count-badge.crash { color: #fca5a5; background: rgba(248, 113, 113, 0.16); }
/* A REPORT THE TABLES DO NOT LIST, NAMED BUT NOT LINKED (2026-10-26, review; app.js
   renderStateIncidentPanel): the link's weight, the body's ink. */
.incident-state-panel .incident-report-name { font-weight: 700; color: var(--text, #0f172a); overflow-wrap: anywhere; }
/* THE MAP'S OWN LINE IN DARK MODE (2026-10-26, review): with no map drawn in it — a report on its way,
   one without FMCSA's detail — the box kept Leaflet's light grey (#ddd, leaflet.css) under the dark
   palette's soft grey, 2:1 (so on HEAD too). A dark well instead, 6:1; light mode keeps its look. */
body.theme-dark #incidentMap:not(:has(.leaflet-pane)) { background: var(--surface, #202023); }

/* Phones: mobile-tables.js makes each row a card (the report its title, as the board's name is) and
   each of the report's tables too; the facts two to a line, and Sort above the cards. */
@media (max-width: 640px) {
    .ib > .ib-bar.pred-vt { display: block; }
    .ib > .ib-bar .pred-vt-bar { grid-template-columns: minmax(0, 1fr); }
    .ib-facts { grid-template-columns: minmax(0, 1fr); gap: 0.75rem; }
    .ib-dl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    table.vb-groups.ib-table[data-m-reflow] td.vb-c-name { min-width: 0; }
    /* A REPORT NUMBER RUN TOGETHER BREAKS INSIDE ITS CARD (2026-10-25, review: one of 42 characters
       ran past the card at 360). mobile.css's break-word for a card's spans outranks .vb-name's
       anywhere, and the toggle's flexbox took the whole token's width. */
    table.ib-table[data-m-reflow] td .vb-name { overflow-wrap: anywhere; min-width: 0; }
    table.ib-table[data-m-reflow] td .vb-toggle { max-width: 100%; }
    /* A VIN, and a plate number behind its label, on a line of their own: in half of one the VIN
       broke mid-string and the label over two lines (2026-10-25, review). A crash's VIN fact has its
       line at every width since 2026-10-26 (above). */
    #pageContent table.ib-sub[data-m-reflow] > tbody > tr > td.ib-wide { grid-column: 1 / -1; }
    /* ONE VALUE TO A LINE ON THE NARROWEST PHONES (2026-10-26, review): a record's card is two values to
       a line, and at 320 half of it is 101px — "INTERNATIONAL" alone is wider. Two to a line while
       each half holds 7rem (as at 360), one to a line under that. NEVER MORE THAN TWO (2026-10-26,
       review): a track for each 7rem put three values on a line at 480 and four at 600–640, wrapping
       beside empty tracks, where the rows' cards, the record's facts and mobile.css's are two. Each
       track at least 40% of the card: room for two, never three. */
    #pageContent .ib-detail table.ib-sub[data-m-reflow] > tbody > tr { grid-template-columns: repeat(auto-fit, minmax(max(7rem, 40%), 1fr)); }
    /* 44px to tap: Try again, the FMCSA link and Show all (2026-10-25, review). A flexbox drops the
       space before the link's arrow, so the gap stands in for it. */
    .ib .ib-retry, .ib .ib-fmcsa a, .ib > .ib-more { display: inline-flex; align-items: center; min-height: 44px; column-gap: 0.3em; }
    /* TRY AGAIN ON A LINE OF ITS OWN (2026-10-26, review): 44px tall on the last line of FMCSA's
       sentence, it opened 10px more above that line than between the others. */
    .ib .ib-line .ib-retry { display: flex; width: fit-content; margin-top: 0.25rem; }
    /* …and the map panel's reports (2026-10-26, review): 21px tall, and now the map's only way into
       the rows. A REPORT NAMED, NOT LINKED, IN THE SAME BOX (2026-10-26, review): it sat 11px lower
       than a linked one beside it. */
    .incident-state-panel a.incident-report-link,
    .incident-state-panel .incident-report-name { display: inline-flex; align-items: center; min-height: 44px; }
    /* An inspection's severity weight in its card: the BASICs run on, " · " between them, each whole;
       two or more take the card's line (incidents-board.js sevHtml). mobile.css lets every span in a
       card wrap, !important; a BASIC and its figure must not part. */
    table.ib-table[data-m-reflow] td.ib-c-sevb .ib-sevb { display: inline; white-space: nowrap !important; }
    table.ib-table[data-m-reflow] td.ib-c-sevb .ib-sevsep { display: inline; }
    table.ib-table[data-m-reflow] > tbody > tr.vb-grp > td.ib-c-sevb:has(.ib-sevsep) { grid-column: 1 / -1; }
    /* …and one BASIC keeps its half (2026-10-26): its note for a screen reader (sevPartHtml) is text
       mobile-tables.js counts, and past 28 characters that gives a cell the card's whole line. */
    table.ib-table[data-m-reflow] > tbody > tr.vb-grp > td.ib-c-sevb:not(:has(.ib-sevsep)) { grid-column: auto; }
    /* THE NOTE STAYS ON ONE LINE (2026-10-26, review): mobile.css lets every span in a card wrap,
       !important, and in its 1px box ", capped at 30: …" fell a letter or two to a line, 34 lines —
       text VoiceOver can join without its spaces. Kept out of that rule. */
    .ib table[data-m-reflow] td .ib-sr { white-space: nowrap !important; overflow-wrap: normal !important; }
    /* A label and a one-word value may part on a phone too, in the rows' cards and the record's (the
       zero-width space of the record's cards from 641px, above). */
    .ib table[data-m-reflow] > tbody > tr > td::before { content: attr(data-label) "\200B"; }
    /* The report's own tables, carded inside the open card: no second frame of their own. */
    #pageContent table.ib-sub[data-m-reflow] > tbody > tr:hover > td,
    body.theme-dark #pageContent table.ib-sub[data-m-reflow] > tbody > tr:hover > td { background-color: transparent !important; }
}
