/* CarrierHelm — FMCSA motor-carrier authority & safety records.
   Design intent: a regulatory inspection sticker, not a SaaS product. A broker vets a carrier in
   about fifteen seconds, often on a phone, outdoors, sometimes reading the DOT number aloud down a
   phone line. So: mobile-first, one screen answers the question, and everything else collapses
   behind native <details>. Committed light + very high contrast — this must survive sunlight.
   Type is a single grotesque at many weights; the restraint is deliberate and utilitarian.
   Colour is status, never decoration: green authorized, red out-of-service, amber caution. */

:root{
  --paper:#FFFFFF; --ground:#EDF0F1; --panel:#F7F9F9;
  --ink:#101619; --ink-2:#41505A; --ink-3:#5E6E78;
  --rule:#C9D2D6; --rule-2:#DFE5E8;
  --brand:#12503A;          /* highway-sign green — chrome only */
  --ok:#0F7A3D; --ok-bg:#E4F3EA;
  --bad:#B81C1C; --bad-bg:#FBE9E9;
  --warn:#8A5200; --warn-bg:#FCF0DD;
  --focus:#12503A;
  /* The histogram's crowd. A neutral slate, not the brand green: the columns are other people's
     carriers and the brand colour belongs to the one this page is about. */
  --bin:#7B8D96; --bin-hi:#41505A;
  --ui:system-ui,-apple-system,"Segoe UI Variable Display","Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --num:ui-monospace,"SF Mono","Segoe UI Mono","Roboto Mono",Menlo,Consolas,monospace;
  color-scheme:light;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
/* The canvas colour lives on the ROOT, not only on body.
   With `html` transparent, the between-documents paint on a same-site navigation falls back to
   white before body's background applies — on a light-grey site that reads as a flash on every
   page change. Declaring it here means the canvas is already the right colour. */
html{background:var(--ground)}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:var(--ui);font-size:17px;line-height:1.5;
  font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;
}
a{color:var(--brand);text-decoration:underline;text-underline-offset:2px}
a:hover{text-decoration-thickness:2px}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px}

.wrap{max-width:760px;margin:0 auto;padding:0 16px}
.wrap--wide{max-width:1080px}

/* ---- masthead: compact, so the verdict is above the fold on a phone ------ */
.masthead{background:var(--brand);color:#fff}
.masthead .wrap{display:flex;align-items:center;gap:16px;min-height:52px}
.logo{font-size:19px;font-weight:800;letter-spacing:-.02em;color:#fff;text-decoration:none}
.logo span{font-weight:400;opacity:.8}
.nav{margin-left:auto;display:flex;gap:16px;font-size:15px;font-weight:600}
.nav a{color:#DCEAE3;text-decoration:none}
.nav a:hover,.nav a[aria-current]{color:#fff;text-decoration:underline}

/* ---- the verdict panel: the whole product in one block ------------------ */
.verdict{background:var(--paper);border:2px solid var(--ink);margin:16px 0;padding:18px 18px 20px}
.verdict__name{font-size:clamp(23px,5.4vw,34px);font-weight:800;letter-spacing:-.02em;line-height:1.14;margin:0 0 2px}
.verdict__dba{font-size:16px;color:var(--ink-2);margin:0 0 14px}
.ids{display:flex;gap:22px;flex-wrap:wrap;padding:13px 0;border-top:1px solid var(--rule-2);border-bottom:1px solid var(--rule-2);margin-bottom:16px}
.id-block{display:flex;flex-direction:column;gap:1px}
.id-block__k{font-size:13.5px;font-weight:700;color:var(--ink-3)}
.id-block__v{font-family:var(--num);font-size:clamp(24px,5.2vw,30px);font-weight:700;letter-spacing:.06em;line-height:1.1}
.copybtn{margin-top:4px;align-self:flex-start;font-size:13.5px;font-weight:600;color:var(--brand);background:none;border:1px solid var(--rule);border-radius:3px;padding:4px 8px;min-height:32px;cursor:pointer}
.copybtn:hover{background:var(--panel)}

/* ---- the ruling, and the facts underneath it ----------------------------
   Five equal chips asserted that five fields matter equally. Two of them decide whether this
   carrier may legally haul the load — operating authority and USDOT registration — and those
   two get the tiles. The safety rating (stale for most carriers, absent for a third of them)
   and the hazmat flag are attributes, so they drop to a quiet fact row: same panel, same data,
   a third of the ink. Colour is still status and still never decoration. */
.ruling{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}
.ruling__cell{min-width:0;display:flex;flex-direction:column;gap:2px;
  padding:13px 15px;border-radius:3px;border-left:8px solid}
.ruling__k{font-size:13.5px;font-weight:600;color:var(--ink-2);letter-spacing:.01em}
.ruling__v{font-size:23px;font-weight:800;letter-spacing:-.015em;line-height:1.1}
.ruling__cell--ok{background:var(--ok-bg);border-color:var(--ok);color:#0B5A2C}
.ruling__cell--bad{background:var(--bad-bg);border-color:var(--bad);color:#8E1414}
.ruling__cell--warn{background:var(--warn-bg);border-color:var(--warn);color:#6B4000}
.ruling__cell--none,.ruling__cell--flat{background:var(--panel);border-color:var(--rule);color:var(--ink-2)}
.ruling__cell--none .ruling__v,.ruling__cell--flat .ruling__v{color:var(--ink)}

.facts{display:grid;grid-template-columns:minmax(0,1fr);gap:0;margin-top:14px;
  border-top:1px solid var(--rule-2)}
.fact{min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;
  align-items:baseline;gap:2px 14px;padding:11px 0;border-bottom:1px solid var(--rule-2)}
.fact:last-child{border-bottom:0}
.fact__k{font-size:14.5px;color:var(--ink-2)}
.fact__v{font-size:16px;font-weight:700;text-align:right}
.fact__v--bad{color:var(--bad)}
.fact__v--warn{color:var(--warn)}
.fact__v--ok{color:var(--ok)}
.fact__n{grid-column:1/-1;font-size:13.5px;color:var(--ink-3);line-height:1.45;max-width:70ch}
@media(min-width:620px){
  .ruling{grid-template-columns:repeat(2,minmax(0,1fr))}
  .facts{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:26px}
  .fact:nth-last-child(2):nth-child(odd){border-bottom:0}
}

/* ---- collapsible detail: native, no JS ---------------------------------- */
.section{background:var(--paper);border:1px solid var(--rule);margin-bottom:10px}
.section>summary{padding:14px 16px;font-weight:700;font-size:16px;cursor:pointer;min-height:48px;display:flex;align-items:center;justify-content:space-between;gap:12px}
.section>summary::-webkit-details-marker{display:none}
.section>summary::after{content:"+";font-family:var(--num);font-size:20px;color:var(--ink-3);font-weight:400}
.section[open]>summary::after{content:"–"}
.section[open]>summary{border-bottom:1px solid var(--rule-2)}
.section__body{padding:4px 16px 16px}
/* `minmax(0,auto)`, never a bare `auto`: an `auto` track sizes to max-content and will starve
   the label beside it. These values are short counts and dates, so the value column may still
   size to itself — it just may no longer refuse to shrink. */
/* A label and its value have to stay associated, and at 1280px they were 1,100px apart —
   "Crashes with a fatality" on the left edge and its number on the right, with nothing between
   them. No overflow, no test failure, and unreadable: a dot-leader problem without the dots.
   Above the reading measure the list becomes columns instead of getting wider, which keeps
   every pair within about 60 characters of each other at any width. */
.kv{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,auto);gap:0;
  column-gap:34px;max-width:62ch}
@media (min-width:1080px){
  /* Two pairs side by side rather than one pair stretched across the page. */
  .kv{max-width:none;grid-template-columns:repeat(2,minmax(0,1fr) minmax(0,auto))}
  .kv dd.kv__n{grid-column:auto/span 2}
}
.kv dt{padding:11px 0;color:var(--ink-2);font-size:15px;border-bottom:1px solid var(--rule-2);
  min-width:0;overflow-wrap:anywhere}
.kv dd{padding:11px 0 11px 14px;margin:0;font-weight:700;text-align:right;
  border-bottom:1px solid var(--rule-2);min-width:0;overflow-wrap:anywhere}
.kv dd.num{font-family:var(--num)}
.locked{color:var(--ink-3);font-weight:400}

.sourceline{background:var(--panel);border:1px solid var(--rule);padding:13px 15px;
  font-size:14.5px;color:var(--ink-2);margin:12px 0;line-height:1.5;max-width:78ch}
.sourceline b{color:var(--ink)}
.sourceline__l{display:block;margin-top:7px;font-size:13.5px;color:var(--ink-3)}

/* THE PROVENANCE STRIP ON THE RECORD PAGE, where the width is.
   `max-width:78ch` on the BOX made this bordered panel 637px wide inside a 1,648px column at
   1920 — stepping a thousand pixels inward from the CRA notice directly beneath it, the
   advertisement directly above it, and the two-column layout above that. Exactly the defect
   already recorded over `.prose` further up this file: the reading measure is what needs
   bounding, not the container. So on the record surface the panel runs the full width like
   every sibling, the SENTENCE keeps its measure, and the width that buys is spent putting the
   provenance and its metadata on one line instead of leaving a thousand pixels of nothing.
   Everywhere else `.sourceline` is a short one-liner inside the 760px wrap and keeps the
   simpler rule above. */
.wrap--rec > .sourceline{max-width:none;display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:space-between;gap:7px 34px}
/* Grows into the space, stops at the measure. `min-width:0` because a flex item defaults to
   `min-width:auto` and refuses to shrink below its longest word. */
.wrap--rec > .sourceline > .sourceline__t{flex:1 1 44ch;min-width:0;max-width:78ch}
.wrap--rec > .sourceline > .sourceline__l{flex:0 1 auto;min-width:0;margin-top:0}

/* ---- search / directory -------------------------------------------------- */
.hunt{background:var(--paper);border:2px solid var(--ink);padding:20px 18px;margin:16px 0}
.hunt h1{font-size:clamp(25px,5.6vw,36px);font-weight:800;letter-spacing:-.022em;line-height:1.12;margin:0 0 8px}
.hunt p{margin:0 0 16px;color:var(--ink-2);font-size:17px;max-width:56ch}
.hunt__form{display:flex;gap:8px;flex-wrap:wrap}
.hunt__form input{flex:1 1 260px;font-family:var(--num);font-size:19px;font-weight:600;padding:13px 14px;border:2px solid var(--ink);border-radius:0;min-height:52px}
.hunt__form button{font-size:17px;font-weight:700;padding:13px 22px;background:var(--brand);color:#fff;border:2px solid var(--brand);border-radius:0;min-height:52px;cursor:pointer}
.hunt__form button:hover{background:#0D3E2C}

.results{list-style:none;margin:14px 0;padding:0}
.results li{background:var(--paper);border:1px solid var(--rule);border-left:6px solid var(--rule);margin-bottom:8px}
.results li.is-ok{border-left-color:var(--ok)}
.results li.is-bad{border-left-color:var(--bad)}
.results a{display:block;padding:14px 16px;text-decoration:none;color:inherit;min-height:48px}
.results a:hover{background:var(--panel)}
.results .nm{font-weight:700;font-size:17px;display:block;margin-bottom:3px}
.results .meta{font-size:14.5px;color:var(--ink-2);font-family:var(--num)}

/* ---- pricing ------------------------------------------------------------- */
.tiers{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));margin:16px 0 28px}
.tier{background:var(--paper);border:1px solid var(--rule);padding:18px}
.tier--anchor{border:2px solid var(--brand)}
.tier__n{font-size:16px;font-weight:800;margin:0 0 4px}
.tier__p{font-family:var(--num);font-size:32px;font-weight:700;letter-spacing:-.02em;margin:0 0 12px}
.tier__p small{font-size:14px;font-weight:600;color:var(--ink-3);font-family:var(--ui)}
.tier ul{list-style:none;margin:0;padding:0;font-size:15px;color:var(--ink-2)}
.tier li{padding:6px 0;border-bottom:1px solid var(--rule-2)}
.btn{display:inline-block;font-size:16px;font-weight:700;padding:12px 20px;background:var(--brand);color:#fff;border:2px solid var(--brand);text-decoration:none;min-height:48px;cursor:pointer}
.btn:hover{background:#0D3E2C}
.btn--quiet{background:transparent;color:var(--brand)}
.btn--quiet:hover{background:var(--panel)}

/* max-width on the BOX made this panel 76px narrower than .cra-notice beside it, so the
   bottom of /about-the-data and /statistics visibly stepped inward. The reading measure is
   what needs bounding, not the container. */
.prose{background:var(--paper);border:1px solid var(--rule);padding:22px 20px;margin:16px 0 30px}
.prose > *{max-width:68ch}
.prose h1{font-size:27px;font-weight:800;letter-spacing:-.02em;margin:0 0 14px}
.prose h2{font-size:18px;font-weight:700;margin:26px 0 8px}
.prose p,.prose li{font-size:16.5px;color:var(--ink-2)}

.foot{padding:24px 0 40px;font-size:15px;color:var(--ink-3)}
.foot nav{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:10px}

/* ---- shared engine chrome ------------------------------------------------ */
.preview-banner{background:var(--warn-bg);border-bottom:2px solid var(--warn);padding:9px 16px;font-size:14.5px;color:#6B4000;display:flex;gap:9px;align-items:baseline;flex-wrap:wrap}
.preview-banner__tag{font-weight:800}
.cra-notice{background:var(--panel);border:1px solid var(--rule);padding:13px 15px;font-size:14.5px;color:var(--ink-2);margin:14px 0}
.cra-notice strong{color:var(--ink)}
.ad-slot{display:flex;align-items:center;justify-content:center;background:var(--panel);border:1px dashed var(--rule);color:var(--ink-3);font-size:13px;margin:14px 0;min-height:100px}
.ad-slot--header{min-height:90px;margin-top:0}
.ad-slot--sidebar{min-height:600px}
.ad-slot--anchor{position:sticky;bottom:0;min-height:60px;margin:0}
.admin-bar{position:sticky;top:0;z-index:50;display:flex;gap:14px;align-items:center;flex-wrap:wrap;background:#101619;color:#EDF0F1;padding:8px 16px;font-size:13.5px;font-weight:600}
.admin-bar select,.admin-bar input{background:#232D33;color:#EDF0F1;border:1px solid #41505A;border-radius:3px;font-size:13.5px;padding:4px 7px;min-height:32px}
.admin-bar__facts{margin-left:auto;display:flex;gap:14px;color:#9DAAB2;font-weight:400;flex-wrap:wrap}
.admin-bar__fact b{color:#EDF0F1}

/* Phone: the masthead nav drops to its own row instead of running off the right edge.
   Mirrors the fix modelwatch.css already carries at max-width:720px. `.nav` has
   margin-left:auto for the desktop row, so it must be reset or it keeps pushing; flex:1 1 100%
   puts it on its own line and its own flex-wrap keeps it safe as links are added (the last one
   is "Sign in"/"Account", so the row grows once a visitor signs in). No hamburger: four links
   fit two rows at 320px, and a disclosure would cost JS for nothing. */
@media (max-width:640px){
  .masthead .wrap{flex-wrap:wrap;gap:6px 16px;padding-top:9px;padding-bottom:9px;min-height:0}
  .nav{margin-left:0;flex:1 1 100%;flex-wrap:wrap;gap:6px 16px}
  /* 24x24 CSS px is the WCAG 2.2 (2.5.8) minimum; the bare links were ~20px tall. */
  .nav a,.foot nav a{padding:3px 0;display:inline-block;min-height:24px}
}
/* iOS Safari zooms the whole page in when a form control smaller than 16px takes focus, and
   leaves it zoomed after — the single most obvious "this was not built for a phone" moment on
   a site. 16px only at phone widths; the designed desktop sizes are untouched. */
@media (max-width:640px){
  input,select,textarea{font-size:16px}
}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ==========================================================================
   Advanced search — the query builder
   Deliberately utilitarian: this is a form on a regulatory site, not a filter
   panel in a SaaS dashboard. Native controls, visible labels, no custom
   widgets — it has to work one-handed on a phone in a truck stop, and it has
   to work with JavaScript off, because /browse is also how crawlers reach the
   corpus.
   ========================================================================== */
.hunt__row{display:flex;gap:8px}
.hunt__form--adv{display:block}
.hunt__form--adv .hunt__row input{flex:1 1 auto;min-width:0}

.builder{margin-top:10px;border:1px solid var(--rule);background:var(--paper);border-radius:6px}
.builder>summary{
  cursor:pointer;padding:10px 14px;font-weight:700;font-size:15px;color:var(--brand);
  list-style:none;display:flex;align-items:center;gap:8px;
}
.builder>summary::-webkit-details-marker{display:none}
.builder>summary::before{content:"▸";font-size:13px;transition:transform .12s}
.builder[open]>summary::before{transform:rotate(90deg)}
.builder__body{padding:4px 14px 14px;border-top:1px solid var(--rule-2)}
.builder__grid{display:grid;gap:12px;grid-template-columns:1fr;align-items:start}
@media(min-width:600px){.builder__grid{grid-template-columns:1fr 1fr}}
@media(min-width:900px){.builder__grid{grid-template-columns:repeat(3,1fr)}}

.fld{display:flex;flex-direction:column;gap:4px;font-size:14px}
.fld>span{font-weight:700;color:var(--ink-2);text-transform:uppercase;letter-spacing:.04em;font-size:12px}
.fld select,.fld input{
  font:inherit;font-size:16px;padding:7px 9px;border:1px solid var(--rule);
  border-radius:4px;background:var(--paper);color:var(--ink);min-width:0;
  /* The builder sits inside .hunt__form, whose `input{flex:1 1 260px}` would otherwise make
     every field grow to fill its grid row — a one-line text box rendering 260px tall. These
     are column-flex children here, so they size to content. */
  flex:0 0 auto;min-height:0;
}
.fld select[multiple]{padding:4px}
.pair{display:flex;gap:6px}
/* Re-grant flex ONLY here: the .fld reset above is what stops a lone input filling its grid
   row, but a min/max pair does need to share the width, and 0 0 auto + width:100% makes the
   two boxes total 200% and pushes the second one out of sight. */
.pair input{flex:1 1 0;width:100%;min-width:0}
.builder__actions{display:flex;gap:10px;align-items:center;margin-top:14px}

.count{margin:14px 0 6px;font-size:15px;color:var(--ink-2);font-weight:600}

/* results get more to say now that the corpus carries fleet + cargo */
.results .meta{display:block}
.results .meta--fleet{color:var(--ink-3)}
.results .cargo{
  display:block;font-size:13px;color:var(--ink-3);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

.pager{display:flex;gap:12px;align-items:center;justify-content:center;margin:20px 0}
.pager__at{font-size:14px;color:var(--ink-2)}

/* ---- daily-allowance panel ---------------------------------------------- */
.quota{
  border:2px solid var(--warn);background:var(--warn-bg);border-radius:6px;
  padding:18px;margin:18px 0;
}
.quota h2{margin:0 0 8px;font-size:19px}
.quota p{margin:0 0 10px;font-size:15px}
.quota__free{color:var(--ink-2);font-weight:600}

/* ---- grouped record detail ----------------------------------------------
   ONE grid, not four two-column tables. The old layout put label and value side by side with an
   `auto` value track, so the value sized itself to its own content and starved the label: at
   most window widths "Cargo authorised to carry" wrapped to one word per line beside a long
   cargo list. That is structural, not a tuning problem — any side-by-side pair sized by content
   has it — so the pair is stacked instead. Nothing here can starve anything, at any width.

   It also cost twenty hairline row rules and four tracked-out uppercase eyebrows, which is most
   of what made this section read as four things rather than one. Grouping now comes from the
   headings alone; they span the full row, so a group's cells sit together beneath their own
   heading and the next heading starts a new row. */
.fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
  gap:15px 26px;margin:0}
.fields__g{grid-column:1/-1;margin:6px 0 0;padding-bottom:5px;font-size:15px;font-weight:700;
  color:var(--ink);border-bottom:1px solid var(--rule-2)}
.fields__g:first-child{margin-top:0}
.field{min-width:0}
.field dt{margin:0 0 1px;font-size:13.5px;line-height:1.35;color:var(--ink-3);
  min-width:0;overflow-wrap:anywhere}
.field dd{margin:0;font-size:16px;font-weight:700;line-height:1.35;
  min-width:0;overflow-wrap:anywhere}
.field dd.num{font-family:var(--num);letter-spacing:-.01em}
/* A list or a sentence gets two cells' worth of width where the grid has two to give. Grid
   clamps a span it cannot honour, so this is a no-op in a single column rather than an
   overflow. */
@supports(grid-column:span 2){.field--wide{grid-column:span 2}}

/* ---- record actions ----------------------------------------------------- */
.rec-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin:16px 0}
.btn--pdf::before{content:"⬇ ";font-weight:700}
/* The key for the star, in words — ONE star and one phrase, whichever describes this reader.
   `flex:1 1 20ch` lets it sit at the end of the row where there is room and drop to its own line
   where there is not; `min-width:0` because a flex item otherwise refuses to shrink below its
   longest word and would widen the whole row. */
.rec-actions__key{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;
  flex:1 1 20ch;min-width:0;font-size:13.5px;color:var(--ink-3)}

/* ══ THE PREMIUM STAR ════════════════════════════════════════════════════════════════════════
   One shape, two states, on premium data, sections and buttons (owner, 2026-09-07). Filled and
   green means the reader HAS this; outlined and grey means it is premium and they do not have
   it yet. It is a reward marker as much as a gate marker — the owner's words were "a Pro user
   should still see PDF button with a star icon" — so a paying reader is shown what their plan
   is giving them rather than only being told what they are missing.

   THE STAR NEVER CARRIES THE MEANING ALONE: `.prem` always prints its word, and where the bare
   glyph rides on a button the action row prints a key. Colour, fill and shape are all
   redundant with text, which is what makes this safe in monochrome and with a screen reader. */
.prem-star{width:11px;height:11px;flex:0 0 auto;fill:currentColor;position:relative;top:.5px}
.prem-star--o{fill:none;stroke:currentColor;stroke-width:1.3;stroke-linejoin:round}
/* On a button the star trails the label — `.btn--pdf` already prints a download arrow in front
   of its own, and two glyphs elbowing each other at the start of one button is noise. */
.btn .prem-star{width:12px;height:12px;margin-left:8px;top:1px}
.locked__cta .prem-star{margin:0 5px 0 0;top:1px}
.prem{display:inline-flex;align-items:center;gap:5px;vertical-align:middle;
  font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;line-height:1;
  color:var(--brand);background:var(--ok-bg);border:1px solid #B9DCC8;padding:4px 6px}
.prem--locked{color:var(--ink-3);background:var(--panel);border-color:var(--rule)}
/* The summary is a flex row with the +/− marker pushed to the far end, so the heading and its
   badge are wrapped together to stay one unit at the left rather than drifting apart. */
.section__t{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px 10px;min-width:0}
/* In the key/value list the badge sits with the label, never in the numeric column: the value
   track is right-aligned tabular figures and a badge in it breaks the column of numbers. */
.kv dt .prem{margin-left:6px}

/* ---- live safety panel -------------------------------------------------- */
.allowed{font-weight:700;margin:0 0 10px;padding:8px 10px;border-radius:4px}
.allowed--yes{background:var(--ok-bg);color:var(--ok)}
.allowed--no{background:var(--bad-bg);color:var(--bad)}
.ins{margin:10px 0 0;font-size:15px}
.ins--none{color:var(--ink-2)}
.fine{margin:12px 0 0;font-size:13.5px;color:var(--ink-3);line-height:1.55;max-width:74ch}

/* ==========================================================================
   Search loader
   A search that returns nothing for two seconds looks broken, and the ad slot
   here is the only thing a free advanced search pays us. Full-screen so it
   cannot be mistaken for part of the results.
   ========================================================================== */
.loader{
  position:fixed;inset:0;z-index:60;background:rgba(16,22,25,.82);
  display:flex;align-items:center;justify-content:center;padding:16px;
}
/* MUST come after the rule above. `display:flex` on a class outranks the user-agent's
   [hidden]{display:none}, so without this the overlay is on screen the moment the page loads —
   which is exactly how it shipped in the first screenshot. */
.loader[hidden]{display:none}
.loader__box{
  background:var(--paper);border-radius:8px;padding:22px;max-width:420px;width:100%;
  text-align:center;box-shadow:0 12px 40px rgba(0,0,0,.35);
}
.loader__t{margin:0 0 14px;font-weight:700;font-size:17px}
.loader__bar{height:4px;background:var(--rule-2);border-radius:2px;overflow:hidden}
.loader__bar span{
  display:block;height:100%;width:40%;background:var(--brand);border-radius:2px;
  animation:cw-slide 1.1s ease-in-out infinite;
}
.loader__f{margin:14px 0 0;font-size:13.5px;color:var(--ink-3)}
.loader .ad-slot{margin:16px 0 0}
@keyframes cw-slide{0%{transform:translateX(-100%)}100%{transform:translateX(250%)}}
@media(prefers-reduced-motion:reduce){
  .loader__bar span{animation:none;width:100%}
}

/* Brand mark in the masthead.
   Applied as a CSS mask rather than an <img> so the glyph takes the masthead's own colour —
   the SVG is authored with fill="currentColor" and an <img> cannot inherit that. One source of
   truth: the same file the PDF letterhead and the favicon use. */
.logo{display:inline-flex;align-items:center}
.logo__mark{
  display:inline-block;width:1.15em;height:1.15em;flex:0 0 auto;margin-right:9px;
  background-color:currentColor;
  -webkit-mask:url(/assets/carrierhelm-mark.svg) center/contain no-repeat;
          mask:url(/assets/carrierhelm-mark.svg) center/contain no-repeat;
}

/* ==========================================================================
   /statistics — the corpus in aggregate
   A breakdown is a real <table> with a bar in each row rather than an SVG
   chart: it is the visual AND the accessible data view at once, needs no
   JavaScript, survives print and forced-colors, and a screen reader gets
   proper row headers. Every value is direct-labelled, so nothing depends on
   reading a bar's length — let alone its colour.
   ========================================================================== */
.stats-hero{margin:22px 0 18px}
.stats-hero h1{font-size:30px;line-height:1.15;letter-spacing:-.02em;margin:0 0 8px}
.stats-hero__lede{font-size:17px;color:var(--ink-2);margin:0 0 8px;max-width:60ch}

/* headline figures */
/* Borders on the items, not a gap-coloured background. auto-fit collapses empty tracks for
   the grid as a whole, never for a wrapped final row — so five figures in a four-column track
   painted the three leftover cells as one grey slab. Same fix already used on .state__list. */
.figs{display:grid;gap:8px;grid-template-columns:repeat(2,1fr);margin:0 0 22px}
/* auto-fit, not a hard 5: it collapses the empty tracks, so a page with four figures gets
   four full-width cells instead of four plus a grey blank where the fifth would be. */
@media(min-width:680px){.figs{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}}
/* Same reasoning as the auto-fit above, for the 2-column phone layout: an odd figure count
   left a grey blank cell where the next one would be. The last item spans instead.
   Guarded to BELOW the auto-fit breakpoint — unguarded it also fired on the desktop
   auto-fit grid and stretched that last figure across every column. */
/* No longer needed: with borders on the items a trailing odd figure leaves real background,
   not a painted cell. Kept as a span only because a lone wide figure reads better than a
   half-width orphan. */
@media(max-width:679px){.figs > .fig:last-child:nth-child(odd){grid-column:1 / -1}}
.fig{background:var(--paper);border:1px solid var(--rule);padding:14px 14px 12px;
  display:flex;flex-direction:column;gap:2px}
/* Proportional figures on purpose: tabular-nums is for columns, and makes a large
   standalone number look loose. */
.fig__v{font-size:28px;font-weight:600;letter-spacing:-.02em;line-height:1.05;font-variant-numeric:normal}
.fig__k{font-size:13px;color:var(--ink-2);font-weight:600}
.fig__n{font-size:12px;color:var(--ink-3);line-height:1.35}

/* jump nav */
.jump{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 22px}
.jump a{
  font-size:13.5px;font-weight:600;text-decoration:none;color:var(--brand);
  border:1px solid var(--rule);padding:5px 10px;border-radius:4px;background:var(--paper);
}
.jump a:hover{border-color:var(--brand);text-decoration:underline}

/* breakdowns */
/* minmax(0,...) + min-width:0 on the items: a track with no explicit size is
   minmax(min-content,max-content), and a grid item's automatic minimum is ALSO its
   min-content — so a long carrier name or an unbreakable date widened this panel past a
   phone viewport and scrolled the whole page sideways. Both halves are needed; fixing
   only the track leaves the item free to overflow it. */
.charts{display:grid;grid-template-columns:minmax(0,1fr);gap:26px;margin:0 0 26px}
.charts>*{min-width:0}
@media(min-width:820px){.charts{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.chart{margin:0;background:var(--paper);border:1px solid var(--rule);padding:16px}
.chart figcaption{margin:0 0 12px}
.chart h3{font-size:17px;margin:0 0 4px}
.chart__note{font-size:13px;color:var(--ink-3);margin:0;line-height:1.4}
.chart table{width:100%;border-collapse:collapse;font-size:14px}
/* The header row carries the units for a screen reader; sighted readers get it from the
   caption, so it is visually hidden rather than duplicated. */
.chart thead th{
  position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;
}
.chart tbody th{
  text-align:left;font-weight:600;padding:5px 10px 5px 0;white-space:nowrap;
  max-width:16ch;overflow:hidden;text-overflow:ellipsis;
}
/* The value gets its own slot rather than trailing the bar: at 100% width the number wrapped
   onto a second line under it, which looked like a rendering fault.
   The flex lives on a span INSIDE the cell, not on the <td> — `display:flex` on a table cell
   takes it out of the table's box model and the column stops growing, which collapsed every
   bar to a stub. */
.chart__cell{width:100%;padding:5px 0}
.chart__row{display:flex;align-items:center;gap:8px}
.chart__track{flex:1 1 auto;min-width:0;display:block}
.chart__bar{
  display:block;height:14px;background:var(--brand);
  /* 4px rounded data-end, square at the baseline — the bar grows from the left edge. */
  border-radius:0 4px 4px 0;min-width:2px;
}
.chart__v{
  font-variant-numeric:tabular-nums;font-weight:600;font-size:13.5px;
  flex:0 0 auto;color:var(--ink);
}
.chart__share{text-align:right;color:var(--ink-3);font-size:12.5px;white-space:nowrap;padding-left:8px}

/* leaderboards — every row is a link into a record, which is half the point */
/* Same minmax(0,...)+min-width:0 reasoning as .charts above. */
.leads{display:grid;grid-template-columns:minmax(0,1fr);gap:26px}
.leads>*{min-width:0}
@media(min-width:820px){.leads{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.lead{background:var(--paper);border:1px solid var(--rule);padding:16px}
.lead h3{font-size:17px;margin:0 0 4px}
.lead__list{list-style:none;margin:12px 0 0;padding:0;counter-reset:none}
.lead__list li{
  display:flex;align-items:baseline;gap:10px;padding:7px 0;
  border-top:1px solid var(--rule-2);font-size:14.5px;
}
.lead__list li:first-child{border-top:0}
.lead__n{
  flex:0 0 auto;width:1.6em;font-variant-numeric:tabular-nums;font-weight:700;
  color:var(--ink-3);font-size:13px;
}
.lead__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead__v{flex:0 0 auto;font-variant-numeric:tabular-nums;font-weight:700}
.lead__v small{font-weight:400;color:var(--ink-3);font-size:12px}

/* The overriding fact.
   A row of chips gives four states equal weight, and 44% of the deactivated carriers in the
   corpus still show an active MC docket — so a reader scanning for "active" finds one. USDOT
   registration is the fact that controls whether a carrier may operate at all, so when it is
   inactive it gets a sentence above the chips rather than a quarter of them. */
.alert{display:block;margin:14px 0 0;padding:12px 14px;border:1px solid;border-left-width:5px}
.alert__t{
  display:block;font-size:14px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  margin-bottom:4px;
}
.alert__b{font-size:15px;line-height:1.45;color:var(--ink)}
.alert--bad{background:var(--bad-bg);border-color:var(--bad)}
.alert--bad .alert__t{color:var(--bad)}
/* Two FMCSA endpoints disagreeing is a caution, not a finding — it must not wear the same red
   as "this carrier is not registered". */
.alert--warn{background:var(--warn-bg);border-color:var(--warn)}
.alert--warn .alert__t{color:var(--warn)}


/* ==========================================================================
   The JSON upsell.
   Shown in place of navigating a free visitor away to /pricing and losing the
   record they came for. Field names only — the values are the thing being
   sold, so a preview that leaked them would defeat its own purpose.
   ========================================================================== */
.upsell{
  position:fixed;inset:0;z-index:80;background:rgba(10,14,16,.72);
  display:flex;align-items:center;justify-content:center;padding:20px;overflow:auto;
}
/* MUST follow the rule above: display:flex on a class outranks [hidden]{display:none}. */
.upsell[hidden]{display:none}
.upsell__box{
  position:relative;background:var(--paper);color:var(--ink);max-width:520px;width:100%;
  padding:26px;box-shadow:0 18px 50px rgba(0,0,0,.4);border:1px solid var(--brand);
}
.upsell__x{
  position:absolute;top:10px;right:12px;background:none;border:0;font-size:26px;line-height:1;
  cursor:pointer;color:inherit;opacity:.55;padding:4px 8px;
}
.upsell__x:hover{opacity:1}
.upsell__box h2{margin:0 0 8px;font-size:21px;padding-right:28px}
.upsell__lede{margin:0 0 14px;font-size:15px;line-height:1.5;opacity:.85}
.upsell__shape{
  margin:0 0 16px;padding:12px 14px;overflow-x:auto;contain:paint;font-size:13px;line-height:1.55;
  background:rgba(127,127,127,.09);border-left:3px solid var(--brand);
}
.upsell__shape code{white-space:pre}
.upsell__list{margin:0 0 18px;padding-left:20px;font-size:15px;line-height:1.7}
.upsell__cta{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 12px}
.upsell__fine{margin:0;font-size:13px;opacity:.65}
@media (prefers-reduced-motion: reduce){.upsell{transition:none}}

/* A price with no button is a leaflet. The checkout API had existed since the billing phase and
   nothing on any site linked to it. */
.tier__cta{display:inline-block;margin-top:14px;width:100%;text-align:center}
.tier__cta--free{opacity:.6;font-size:13.5px;padding:10px 0;display:block}

/* ── /account ─────────────────────────────────────────────────────────────────────────
   Filing-cabinet plainness, same as the record: squared corners, a hard rule, the state
   carried by text colour rather than a fill. Nothing here should feel like a SaaS dashboard;
   it is the same document furniture as everything else on the site. */
.acct{max-width:760px;margin:0 auto;padding:8px 0 40px}
.acct__top{margin:0 0 18px}
.acct__top h1{font-size:26px;margin:0 0 4px;letter-spacing:-.01em}
.acct__who{margin:0;color:var(--ink-2);font-size:14px}
.acct__card{background:var(--paper);border:1px solid var(--rule);padding:20px 20px 22px;margin:0 0 14px}
.acct__card h2{font-size:15px;margin:0 0 4px;letter-spacing:.02em;text-transform:uppercase;color:var(--ink-2)}
.acct__planhead{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}
.acct__eyebrow{margin:0;font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3)}
.acct__planhead h2{font-size:26px;margin:2px 0 0;text-transform:none;letter-spacing:-.01em;color:var(--ink)}
.acct__state{margin:0;font-weight:700;font-size:14px;letter-spacing:.02em}
.acct__state[data-tone="ok"]{color:var(--ok)}
.acct__state[data-tone="warn"]{color:var(--warn)}
.acct__state[data-tone="bad"]{color:var(--bad)}
.acct__state[data-tone="none"]{color:var(--ink-3)}
.acct__detail{margin:8px 0 0;color:var(--ink-2);font-size:14.5px}
.acct__points{margin:14px 0 0;padding:0 0 0 18px;color:var(--ink-2);font-size:14.5px}
.acct__points li{margin:3px 0}
.acct__meter{margin:14px 0 0}
.acct__meterhead{display:flex;justify-content:space-between;font-size:14px;gap:12px}
.acct__meterhead strong{font-variant-numeric:tabular-nums;font-weight:600}
.acct__bar{height:6px;background:var(--ground);margin-top:6px;border:1px solid var(--rule)}
.acct__bar span{display:block;height:100%;background:var(--brand)}
.acct__bar[data-spent="1"] span{background:var(--bad)}
.acct__offers{display:grid;gap:12px;margin-top:14px;justify-content:start;
  /* A capped track, not 1fr: with one upgrade left, auto-fit stretched a single card the
     full width of the page over dead space. */
  grid-template-columns:repeat(auto-fit,minmax(210px,300px))}
.acct__offer{border:1px solid var(--rule);padding:16px}
.acct__offer h3{margin:0;font-size:16px}
.acct__price{margin:2px 0 10px;font-size:24px;font-weight:700;font-variant-numeric:tabular-nums}
.acct__price span{font-size:13px;font-weight:400;color:var(--ink-3)}
.acct__offer ul{margin:0 0 14px;padding:0 0 0 17px;font-size:13.5px;color:var(--ink-2)}
.acct__actions{display:flex;gap:10px;flex-wrap:wrap;margin:20px 0}
.acct__foot{color:var(--ink-3);font-size:13px;margin:18px 0 0;max-width:62ch}
.acct--out .acct__detail{max-width:58ch}

/* State ranking + fleet tables. Real tables: this is tabular data. */
/* `contain:paint` is what actually stops a wide child handing its overflow back to the PAGE.
   max-width:100%, width:100% and overflow-x:clip on the parent all do nothing — measured on the
   pricing matrix, which scrolled 364px internally AND 217px sideways at the same time, and is
   invisible in a screenshot. Detect it with scrollTo(9999,0) then read scrollX. */
.tablewrap{overflow-x:auto;contain:paint;margin-top:14px}
.ranktable{width:100%;border-collapse:collapse;font-size:14.5px;min-width:560px;background:var(--paper)}
.ranktable th,.ranktable td{text-align:right;padding:9px 11px;border-bottom:1px solid var(--rule);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.ranktable thead th{font-size:11.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-2);
  border-bottom:2px solid var(--ink);font-weight:700}
.ranktable th[scope=row]{text-align:left;font-weight:500;white-space:normal}
/* Split: these positional rules were written for the RANK table (col 1 = rank, col 2 = state)
   and were also hitting the FLEET table (col 1 = carrier name), which right-aligned the CARRIER
   header over left-aligned names and starved the name column to ~3ch. A header must always
   share its column's alignment. */
.ranktable--rank thead th:first-child{text-align:right;width:3ch}
.ranktable--rank thead th:nth-child(2){text-align:left}
.ranktable--rank th[scope=row]{min-width:16ch}
.ranktable--fleet thead th:first-child{text-align:left;width:auto}
.ranktable--fleet th[scope=row]{width:100%;min-width:22ch}
.ranktable--fleet thead th:not(:first-child),.ranktable--fleet td{width:1%}
.ranktable td[data-lead="1"]{font-weight:700}
.ranktable tbody tr:hover{background:var(--panel)}
.state__rank{margin:14px 0 0;font-size:15.5px;color:var(--ink-2)}
.state__others{margin:26px 0 0}
.state__otherlede{margin:4px 0 0;color:var(--ink-2);font-size:14.5px;max-width:66ch}
.state__fleet{margin:26px 0 0}
/* Borders on the items, NOT a gap-coloured grid background: with 5 items in a 3-column track
   the trailing empty cell painted itself as a grey block. */
.state__list{list-style:none;padding:0;margin:14px 0 0;display:grid;gap:8px;
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.state__list li{background:var(--paper);border:1px solid var(--rule);display:flex;
  justify-content:space-between;gap:10px;padding:9px 12px;font-size:14.5px}
.state__list span{font-variant-numeric:tabular-nums;color:var(--ink-2)}

/* ---- term definitions: a tray, not a bubble ------------------------------
   Two previous attempts anchored a bubble to the word and tried to clamp it inside the
   viewport. Neither worked, and neither could: an absolutely positioned box grows away from
   whichever edge you pin it to, and CSS cannot ask which edge is nearer. Measured at 768 and
   1100 with the last attempt in place, all nine definitions on a record page were clipped, by
   up to 66px.

   So the bubble stops chasing the word. The definition opens as a tray fixed to the foot of
   the VIEWPORT, at every width, capped at a comfortable measure and centred. It cannot escape
   the screen because it is positioned against the screen — there is no case left to get wrong,
   in any browser, at any width, at any zoom. It also suits the content: several of these
   definitions run to sixty words, which was never going to be a tooltip.

   The tray leads with the term name (glossary.js puts it there), because a panel at the bottom
   of the screen has to say what it is defining. Hover, focus and touch all open it; `title`
   alone would be invisible to a keyboard and unreachable on a phone. No JS. */
.term{border-bottom:1px dotted var(--ink-3);cursor:help;outline-offset:3px}
.term::after{
  content:attr(data-def);position:fixed;z-index:60;
  left:50%;bottom:14px;transform:translateX(-50%);
  width:min(620px,calc(100vw - 24px));padding:13px 16px;
  background:var(--ink);color:var(--paper);font-size:14px;font-weight:400;line-height:1.5;
  text-align:left;border-radius:4px;box-shadow:0 8px 30px rgba(0,0,0,.34);
  opacity:0;visibility:hidden;transition:opacity .12s ease;pointer-events:none;
}
.term:hover::after,.term:focus-visible::after{opacity:1;visibility:visible}
@media(prefers-reduced-motion:reduce){.term::after{transition:none}}
/* A gloss that is itself the explanation of a code — "C compliance review" — reads as part of
   the value, not as an annotated label. */
.term--gloss{font-weight:400;color:var(--ink-2);font-size:14.5px}

/* ── Wide displays ────────────────────────────────────────────────────────────────────
   The page is built mobile-first and stays a single column up to 1100px. Past that a
   phone-shaped ribbon of content in the middle of a desktop screen is wasted space, so the
   record's detail sections flow into two columns. The verdict panel, the actions and the
   source line stay full width: they are the answer, and the answer should not be hunted for
   in a column. `align-items:start` stops a short section stretching to match a tall one. */
/* ── Wide displays ────────────────────────────────────────────────────────────────────
   A fixed grid, NOT balanced columns. Multi-column has one degree of freedom — how many —
   with equal tracks and emergent order, and a record needs the opposite. Measured at a true
   1920 viewport, `columns:3` left the entire third track EMPTY (~430px) because one child
   was taller than the other three combined and break-inside made that height the floor. It
   was also unstable: collapsing one <details> moved an unrelated section to a different
   column, so positional memory never formed for someone checking twenty carriers a day. */
@media(min-width:1100px){
  .wrap--rec{max-width:1240px}
  .rec-layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:28px;align-items:start}
  /* No rail, no two-track grid. A paying reader has nothing to put in it. */
  .rec-layout--full{display:block}
  /* The rail sticks: provenance and any rail unit stay reachable through a long record. */
  .rec-rail{position:sticky;top:16px;display:grid;gap:14px}

  /* One content column plus the rail until there is genuinely room for two. Paired at 1100 the
     tracks were ~300px and labels like "Inspections ending in an out-of-service order" wrapped
     to three lines — two cramped columns are worse than one comfortable one. */
  .rec-cols{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;align-items:start}
  .rec-cols > .section{margin:0}
  .rec-cols > .section--wide{grid-column:1 / -1}

  /* Nothing extra is needed for the detail section any more: `.fields` is already a width-driven
     grid of stacked cells, so it spends whatever width it is given without a second grid on top
     of it deciding how many columns of two-column lists to make. Removing that layer is what
     fixed the awkward middle — around 900 to 1280px it produced two ~336px columns, which is
     exactly too narrow for a label and a value side by side. */
  .rec-cols .kv dd small{display:block;margin-top:2px}
}
@media(min-width:1400px){
  /* Now the tracks are ~450px, which is where these labels stop wrapping. Inspections and
     crashes pair here — they were built to, at 578 and 508px tall. */
  .rec-cols{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* Not everything pairs. The comparison block, the notice that stands in for it, and the
     in-content advertisement all run the full width: the first two are the page's second
     answer and reading half-width beside a crash list demotes them, and a 260px ad box in one
     track is a hole in the layout rather than a unit. */
  .rec-cols > .section--rank,
  .rec-cols > .nodata,
  .rec-cols > .ad-slot{grid-column:1/-1}
}
@media(min-width:1500px){
  .wrap--rec{max-width:1440px}
  .rec-layout{grid-template-columns:minmax(0,1fr) 336px}
}

/* ── On-page checkout ─────────────────────────────────────────────────────────────────
   Stripe's own form mounts inside .pay__mount; everything around it is ours. Nothing here
   styles an input, because we never render one — the card fields belong to Stripe. */
/* The dialog must never be taller than the screen it opens on. It scrolls as a whole, the
   payment step gets most of the height, and the bottom padding is real so the last field and
   the Pay button are never flush against the viewport edge — which is what cut the form off. */
.pay{position:fixed;inset:0;z-index:100;background:rgba(16,22,25,.55);
  display:flex;align-items:flex-start;justify-content:center;
  padding:24px 16px 48px;overflow-y:auto;overscroll-behavior:contain}
.pay[hidden]{display:none}
.pay__box{position:relative;background:var(--paper);border:1px solid var(--rule);
  width:100%;max-width:560px;padding:26px 24px 22px;box-shadow:0 24px 70px rgba(0,0,0,.3);
  margin-bottom:24px}
.pay__x{position:absolute;top:8px;right:10px;border:0;background:none;font-size:26px;
  line-height:1;color:var(--ink-3);cursor:pointer;padding:4px 8px}
.pay__box h2{margin:0 0 6px;font-size:22px;letter-spacing:-.01em}
.pay__lede{margin:0 0 18px;color:var(--ink-2);font-size:15px}
.pay__opts{display:grid;gap:10px}
.pay__opt{display:grid;grid-template-columns:1fr auto;gap:2px 12px;text-align:left;width:100%;
  background:var(--paper);border:1px solid var(--rule);padding:14px 16px;cursor:pointer;
  font:inherit;color:inherit;text-decoration:none}
.pay__opt:hover,.pay__opt:focus-visible{border-color:var(--brand);background:var(--panel)}
.pay__opt--one{border-width:2px;border-color:var(--brand)}
.pay__opt-n{font-weight:700;font-size:16px}
.pay__opt-p{font-weight:700;font-size:20px;font-variant-numeric:tabular-nums;text-align:right}
.pay__opt-p small{font-size:12px;font-weight:400;color:var(--ink-3)}
.pay__opt-d{grid-column:1/-1;font-size:13.5px;color:var(--ink-2);line-height:1.45}
.pay__fine{margin:16px 0 0;font-size:12.5px;color:var(--ink-3);line-height:1.5}
.pay__back{border:0;background:none;color:var(--brand);cursor:pointer;font:inherit;padding:0 0 12px}
/* Stripe's embedded iframe auto-sizes by reporting its content height to the parent. Inside
   this overlay it reported 0 and stayed there, so the dialog opened blank with a working form
   inside it. Constraining the mount and forcing the iframe to fill it is the supported way out:
   Stripe scrolls internally, and the form is ~1,100px tall anyway — taller than most viewports,
   so a scrollable panel is the better result regardless.
   The !important is load-bearing: Stripe writes `height: 0` as an inline style, and an author
   !important is the only thing that outranks it. */
/* Tall enough that Stripe's form is usable without an inner scrollbar wherever it fits, and
   bounded by the viewport so the modal itself stays scrollable rather than overflowing it. */
/* The framed Keelhelm ID page (the Account step). It reports its own height over postMessage,
   so the height set here is only the pre-load floor; pay.js clamps whatever it is told. */
.pay__idhost{min-height:190px}
.pay__idframe{display:block;width:100%;height:190px;border:0}

.pay__mount{min-height:460px;height:calc(100vh - 220px);max-height:820px}
.pay__mount > iframe{height:100%!important;width:100%!important;border:0}
@media(prefers-reduced-motion:no-preference){.pay__opt{transition:border-color .12s,background .12s}}
/* The complete-record CTA sits beside the free download rather than replacing it: the basic
   PDF is the shareable artefact and should stay one click away. */
/* SCOPED TO THE QUIET VARIANT. Unscoped, this set `color:var(--brand)` on any `.btn--buy` and
   left the background alone — so a SOLID buy button rendered brand-green text on a brand-green
   fill and its label vanished completely. Caught in the contrast audit, 2026-09-07. */
.btn--quiet.btn--buy{border-color:var(--brand);color:var(--brand);font-weight:700}
.btn--quiet.btn--buy:hover,.btn--quiet.btn--buy:focus-visible{background:var(--brand);color:#fff}

/* ── Staged checkout ──────────────────────────────────────────────────────────────────
   The rail is a 1:1 map of the flow. Completed steps are buttons (Baymard: users try to click
   them to go back); future steps are inert. */
.pay__steps{display:flex;gap:0;list-style:none;margin:0 0 20px;padding:0 0 14px;
  border-bottom:1px solid var(--rule);counter-reset:none}
.pay__step{flex:1 1 0;min-width:0}
.pay__step[hidden]{display:none}
.pay__stepback{display:flex;align-items:center;gap:7px;width:100%;border:0;background:none;
  font:inherit;font-size:12.5px;color:var(--ink-3);padding:0;text-align:left;cursor:default}
.pay__step.is-done .pay__stepback{cursor:pointer;color:var(--ink-2)}
.pay__step.is-done .pay__stepback:hover,.pay__step.is-done .pay__stepback:focus-visible{color:var(--brand)}
.pay__stepn{flex:0 0 auto;width:21px;height:21px;border-radius:50%;border:1px solid var(--rule);
  display:grid;place-items:center;font-size:11.5px;font-weight:700;background:var(--paper)}
.pay__step.is-now .pay__stepn{background:var(--brand);border-color:var(--brand);color:#fff}
.pay__step.is-now .pay__stepback{color:var(--ink);font-weight:600}
.pay__step.is-done .pay__stepn{background:var(--ok-bg);border-color:var(--ok);color:var(--ok)}
.pay__steplabel{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:520px){.pay__steplabel{display:none}}

/* The total stays visible from the moment a plan is chosen and before card details are asked
   for — Baymard's payment-UX rule, and the thing that stops "wait, how much was that?". */
.pay__summary{margin:0 0 16px;padding:9px 12px;background:var(--panel);border:1px solid var(--rule);
  font-size:14px;font-weight:600;color:var(--ink)}
.pay__summary[hidden]{display:none}
.pay__actions{display:flex;gap:10px;flex-wrap:wrap;margin:18px 0 0}

/* "No comparison is possible." Not an error and not a teaser — a finding, in the same register
   as any other fact on the page. Someone who never pays is still owed the difference between
   "this carrier has a clean record" and "FMCSA has no record here". */
.nodata{background:var(--panel);border:1px solid var(--rule);border-left:4px solid var(--ink-3);
  padding:15px 17px;margin:0 0 16px}
.nodata__p{margin:0 0 8px;font-size:15.5px;color:var(--ink-2);line-height:1.5;max-width:62ch}
.nodata__p:last-child{margin-bottom:0;font-size:14.5px}

/* ══ THE RECORD PAGE, SECOND PASS ═══════════════════════════════════════════════════════════
   Everything below dates from the record-page redesign. Three things drove it: the header was
   asserting five equal facts, the out-of-service rate was being printed without the denominator
   or the direction that make a rate mean anything, and the paid half of the product was
   invisible on the page it is sold from. */

/* ---- a qualifier gets its own grid row ------------------------------------
   It used to sit inside the value cell. The `auto` value track then sized itself to the
   longest qualifier on the list — "24-month crashes over 2 × 3,221,711,602 miles reported for
   2025" — and starved the label column, so at 1920 "Crashes with a tow-away" wrapped onto three
   lines while two thirds of the row sat empty. Its own row costs nothing and gives the label
   its width back at every size. */
/* `.kv dd` sets text-align:right, so the note needs the same specificity to sit under the
   label where it belongs — as `.kv__n` alone it lost the cascade and floated mid-row. */
.kv dd.kv__n{grid-column:1/-1;margin:0;padding:0 0 11px;font-size:13.5px;color:var(--ink-3);
  line-height:1.4;text-align:left;border-bottom:1px solid var(--rule-2)}
.kv dt:has(+ dd + .kv__n),.kv dt:has(+ dd + .kv__n) + dd{border-bottom:0;padding-bottom:2px}

/* A locked row offers the way in rather than showing a dead grey label. */
.locked__cta{font:inherit;font-weight:600;font-size:14.5px;color:var(--brand);background:none;
  border:0;border-bottom:1px solid currentColor;padding:0;cursor:pointer;min-height:24px}
.locked__cta:hover,.locked__cta:focus-visible{color:#0D3E2C}

/* ---- out-of-service orders ------------------------------------------------
   The one number a broker acts on, so it gets a block of its own rather than a row in a list.

   COLOUR, ADDED 2026-09-07 AT THE OWNER'S REQUEST, AND KEPT ON A LEASH. Better than the
   agency's own published average is positive, worse is cautionary, and a tile with too few
   inspections to rate stays grey. NO RED anywhere: this is our arithmetic on a federal record
   beside the agency's own average, and red reads as an accusation about a carrier that has not
   been accused of anything. Colour never carries information on its own either — every tile
   still spells out "below"/"above the national average of x%" — so nothing is lost to a reader
   who cannot see the difference between the two tints. */
.oos{margin:18px 0 0;border-top:1px solid var(--rule-2);padding-top:16px}
.oos__h{margin:0;font-size:16.5px;font-weight:700;display:flex;flex-wrap:wrap;align-items:baseline;
  gap:6px 12px}
.oos__dir{font-size:13.5px;font-weight:600;color:var(--ink-3)}
.oos__lede{margin:6px 0 14px;font-size:15px;color:var(--ink-2);line-height:1.45;max-width:62ch}
.oos__grid{display:grid;grid-template-columns:minmax(0,1fr);gap:10px}
@media(min-width:560px){.oos__grid{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))}}
.oos__tile{min-width:0;display:flex;flex-direction:column;gap:2px;
  background:var(--panel);border:1px solid var(--rule);border-left:5px solid var(--ink-3);
  padding:12px 14px 13px}
.oos__tile--ok{background:var(--ok-bg);border-color:#B9DCC8;border-left-color:var(--ok)}
.oos__tile--warn{background:var(--warn-bg);border-color:#E8CFA0;border-left-color:var(--warn)}
.oos__tile--ok .oos__v{color:#0B5A2C}
.oos__tile--warn .oos__v{color:#6B4000}
.oos__tile--ok .oos__cmp{color:#0B5A2C}
.oos__tile--warn .oos__cmp{color:#6B4000}
.oos__k{font-size:14px;font-weight:700;color:var(--ink-2)}
.oos__v{font-family:var(--num);font-size:30px;font-weight:700;letter-spacing:-.02em;
  line-height:1.05;margin:2px 0 4px;overflow-wrap:anywhere}
.oos__tile--none .oos__v{font-size:23px;color:var(--ink-2)}
.oos__cmp{font-size:14.5px;font-weight:600;color:var(--ink);line-height:1.35}
.oos__basis{font-size:13.5px;color:var(--ink-3);line-height:1.4;margin-top:5px}
.oos__tile--ok .oos__basis,.oos__tile--warn .oos__basis{color:var(--ink-2)}

/* ══ HOW THIS CARRIER COMPARES ══════════════════════════════════════════════════════════════
   The histogram that replaced the rank bars. Bars were rejected twice and the reason is
   structural: a bar carries one number, and mean, median, spread and outlier are properties of
   a distribution. See src/site/histogram.js.

   NO JAVASCRIPT ANYWHERE IN HERE. The group switcher is a radio group whose labels are styled
   as tabs; `:checked ~` reveals the matching panel. It works with scripting off, arrow keys move
   between groups for free, and with CSS off as well every panel simply renders stacked. */
.section--rank .section__body{padding-bottom:18px}
/* One measure for the whole component. At 1440 the comparison spans both content tracks, and a
   full-bleed tab strip over a centred chart reads as two different widths arguing. */
.hg-wrap{max-width:700px;margin:0 auto 4px}
.hg-radio{position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none}

/* 1px gaps over a ruled background draw every divider at once, so no tab needs an edge rule
   that would double up against the container at the end of a wrapped row. */
.hg-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(116px,1fr));
  gap:1px;background:var(--rule);border:1px solid var(--rule);border-bottom:0}
.hg-tab{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  min-height:56px;padding:9px 8px;text-align:center;cursor:pointer;background:var(--panel);
  color:var(--ink-2);font-size:14.5px;line-height:1.25;min-width:0}
.hg-tab b{font-weight:700;min-width:0;overflow-wrap:anywhere}
.hg-tabn{font-size:13px;color:var(--ink-3)}
.hg-tab:hover{background:#E7ECED}
.hg-panels{border:1px solid var(--rule);background:var(--paper);padding:16px 14px 15px}

.hg-panels>.hg-panel{display:none}
.hg-radio:nth-of-type(1):checked~.hg-panels>.hg-panel:nth-child(1),
.hg-radio:nth-of-type(2):checked~.hg-panels>.hg-panel:nth-child(2),
.hg-radio:nth-of-type(3):checked~.hg-panels>.hg-panel:nth-child(3),
.hg-radio:nth-of-type(4):checked~.hg-panels>.hg-panel:nth-child(4){display:block}
.hg-radio:nth-of-type(1):checked~.hg-tabs>.hg-tab:nth-child(1),
.hg-radio:nth-of-type(2):checked~.hg-tabs>.hg-tab:nth-child(2),
.hg-radio:nth-of-type(3):checked~.hg-tabs>.hg-tab:nth-child(3),
.hg-radio:nth-of-type(4):checked~.hg-tabs>.hg-tab:nth-child(4){background:var(--brand);color:#fff}
.hg-radio:nth-of-type(1):checked~.hg-tabs>.hg-tab:nth-child(1) .hg-tabn,
.hg-radio:nth-of-type(2):checked~.hg-tabs>.hg-tab:nth-child(2) .hg-tabn,
.hg-radio:nth-of-type(3):checked~.hg-tabs>.hg-tab:nth-child(3) .hg-tabn,
.hg-radio:nth-of-type(4):checked~.hg-tabs>.hg-tab:nth-child(4) .hg-tabn{color:#CFE3D9}
.hg-radio:nth-of-type(1):focus-visible~.hg-tabs>.hg-tab:nth-child(1),
.hg-radio:nth-of-type(2):focus-visible~.hg-tabs>.hg-tab:nth-child(2),
.hg-radio:nth-of-type(3):focus-visible~.hg-tabs>.hg-tab:nth-child(3),
.hg-radio:nth-of-type(4):focus-visible~.hg-tabs>.hg-tab:nth-child(4){outline:3px solid var(--ink);
  outline-offset:-3px}

/* The finding, in one line. Typical is GREY because it is the absence of a finding rather than
   a mild warning; worse-than-most is amber; red is retired from this section entirely. */
.hg-v{display:flex;gap:10px;align-items:flex-start;margin:0 0 13px;padding:11px 13px;
  border-left:4px solid var(--rule);font-size:15px;line-height:1.45}
.hg-v b{display:block;font-size:16.5px;margin-bottom:1px}
.hg-vi{flex:0 0 auto;width:16px;height:16px;margin-top:4px;fill:currentColor}
.hg-v--ok{background:var(--ok-bg);border-left-color:var(--ok);color:#0B5A2C}
.hg-v--typ{background:var(--panel);border-left-color:var(--ink-3);color:var(--ink-2)}
.hg-v--warn{background:var(--warn-bg);border-left-color:var(--warn);color:#6B4000}
.hg-caution{display:flex;gap:9px;align-items:flex-start;margin:0 0 13px;padding:10px 12px;
  background:var(--warn-bg);border-left:4px solid var(--warn);color:#6B4000;
  font-size:14.5px;line-height:1.45}

/* ---- the plot ------------------------------------------------------------
   Geometry in SVG, every WORD in HTML positioned over it. Text inside a viewBox scales with the
   box, and this chart renders anywhere from 280px to 620px wide — one font-size declaration
   would land at 8.6px on a phone and 17px on a desktop. So the labels are ordinary HTML at
   ordinary pixel sizes, placed by percentages taken from the same coordinates the SVG uses. */
.hg-plot{max-width:620px;margin:0 auto;overflow:hidden}
/* The chart's own title. It is the x axis's quantity, which is why the x axis carries ticks but
   no second label under them. It WRAPS at 375px rather than truncating: an axis title that ends
   in an ellipsis has stopped being an axis title. */
.hg-title{margin:0 0 7px;font-size:14px;font-weight:700;color:var(--ink);line-height:1.35;
  max-width:52ch;text-wrap:balance}
/* The y axis's title, horizontal above the axis rather than rotated. Rotated it would need its
   own column of width beside the tick values, and at 375px the plot cannot spare it. */
.hg-ytitle{margin:0 0 1px;font-size:12.5px;color:var(--ink-3);line-height:1.3}
.hg-frame{position:relative;padding-top:21px}
.hg-box{position:relative}
svg.hg{display:block;width:100%;height:auto}
.hg-bar{fill:var(--bin)}
.hg-grid{stroke:var(--rule-2);stroke-width:1}
.hg-axis,.hg-tick,.hg-break{stroke:#8FA0A8;stroke-width:1;fill:none}
.hg-break{stroke-width:1.2}
.hg-halo{stroke:var(--paper);stroke-width:4.5}
.hg-rule{stroke:var(--brand);stroke-width:2.5}
.hg-ci{stroke:var(--brand);stroke-width:2}

.hg-pin{position:absolute;top:0;left:0;transform:translateX(6px);white-space:nowrap;
  font-size:13.5px;font-weight:700;color:var(--brand);line-height:1.3}
.hg-pin--l{transform:translateX(calc(-100% - 6px))}

/* Transparent hit areas over the columns. A span rather than a button: nothing here is an
   action, and eleven buttons in a chart would be eleven promises the page cannot keep. */
.hg-hit{position:absolute;top:21.43%;height:74.29%;cursor:default}
.hg-hit:hover,.hg-hit:focus-visible{background:rgba(65,80,90,.10)}
.hg-hit:focus-visible{outline:2px solid var(--ink);outline-offset:0}
.hg-read{position:absolute;top:2px;left:50%;transform:translateX(-50%);
  white-space:nowrap;background:var(--ink);color:var(--paper);
  font-size:13px;font-weight:600;padding:4px 8px;opacity:0;pointer-events:none;z-index:2}
.hg-read--l{left:0;transform:none}
.hg-read--r{left:auto;right:0;transform:none}
.hg-hit:hover .hg-read,.hg-hit:focus-visible .hg-read{opacity:1}

.hg-xlabs{position:relative;height:19px;margin-top:1px}
.hg-xl{position:absolute;top:0;transform:translateX(-50%);font-size:13px;color:var(--ink-3);
  line-height:1.4}

/* Y AXIS VALUES. Right-aligned into the gutter the plot reserves for them, one per gridline, at
   a fixed pixel size like every other word here. `width` arrives inline from the same PLOT.x the
   SVG measured the gutter with, so the two can never drift apart. */
.hg-yl{position:absolute;left:0;transform:translateY(-50%);text-align:right;
  font-size:11.5px;color:var(--ink-3);line-height:1;white-space:nowrap;
  font-variant-numeric:tabular-nums}

.hg-key{list-style:none;display:grid;grid-template-columns:minmax(0,1fr);gap:6px 22px;
  margin:14px 0 0;padding:0;font-size:14px;color:var(--ink-2)}
@media(min-width:540px){.hg-key{grid-template-columns:repeat(2,minmax(0,1fr))}}
.hg-key li{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;line-height:1.35;min-width:0}
.hg-key b{color:var(--ink);white-space:nowrap}
.hg-kn{color:var(--ink-3);font-size:13.5px}
.hg-k{flex:0 0 auto;width:15px;height:11px;position:relative;top:1px;background:var(--bin)}
.hg-k--subj{width:15px;background:linear-gradient(var(--brand),var(--brand)) center/3px 100% no-repeat}
.hg-basis{margin:10px 0 0;font-size:13.5px;color:var(--ink-3);line-height:1.45;max-width:70ch}

/* Stacked, for the PDF and for a single group. */
.hg-wrap--stack .hg-panel+.hg-panel{margin-top:22px;padding-top:20px;border-top:1px solid var(--rule-2)}
/* The key and the caution are about THIS CARRIER, so they read identically in every stacked
   panel. Once is enough when they are all on screen at the same time; the tabbed layout keeps
   them everywhere because only one panel is ever visible there. */
.hg-wrap--stack .hg-panel:not(:first-child) .hg-key,
.hg-wrap--stack .hg-panel:not(:first-child) .hg-caution{display:none}
.hg-ph{margin:0 0 9px;font-size:15.5px;font-weight:700}

/* ---- what a free reader sees instead --------------------------------------
   It DESCRIBES the chart rather than drawing a greyed-out one. A silhouette would be a picture
   with no data behind it standing where a picture with data belongs, which is the one thing a
   records product cannot publish. Nothing here is computed: the group names come from two
   numbers already printed on this page, so a free pageview still costs no peer query. */
.locked-cmp{background:var(--panel);border:1px solid var(--rule);padding:16px 17px;
  background-image:repeating-linear-gradient(45deg,rgba(94,110,120,.05) 0 4px,transparent 4px 11px)}
.locked-cmp__h{margin:0 0 6px;font-size:16.5px;font-weight:700;color:var(--ink)}
.locked-cmp__p{margin:0 0 8px;font-size:15px;color:var(--ink-2);line-height:1.5;max-width:60ch}
.locked-cmp__g{margin:0;font-size:14px;color:var(--ink-3);line-height:1.5;max-width:66ch}

/* Two ways in, not one: a plan, and this one record at its own price. The record button skips
   the plan chooser entirely (pay.js reads data-pay-record), which is the point of having it. */
.buyrow{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin:16px 0 0}
.buyrow__n{font-size:14px;color:var(--ink-3);flex:1 1 12ch;min-width:0}

.statute{margin:16px 0 0;padding:0 0 0 12px;border-left:3px solid var(--rule);
  font-size:13.5px;color:var(--ink-3);line-height:1.5;max-width:78ch}
.statute__src{display:block;margin-top:3px}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* ---- advertising: reserved, layout-stable, and never beside "we have nothing" ----
   Every unit declares its height before anything loads, so turning a real network on later
   cannot shift the record under a reader's thumb. The mid-page unit is rendered by the template
   only when a safety section exists above it (see brands/carrierwatch.js) — an advertisement
   directly under "this carrier cannot be compared with others" is the worst placement on the
   site, and CSS cannot prevent that one, only the template can. */
.ad-slot{margin:18px 0}
.ad-slot--header{min-height:100px;margin-top:4px}
.ad-slot--in-content-1,.ad-slot--in-content-2{min-height:260px}
.ad-slot--sidebar{min-height:600px;margin:0}
.rec-cols > .ad-slot{margin:0}

/* ---- the record grid, 375 → 1920 -----------------------------------------
   One column on a phone; content plus a sticky rail from 1100; two content columns from 1400,
   which is where these labels stop wrapping; and a wider page from 1800 rather than 240px of
   empty gutter each side. `minmax(0,1fr)` on every container and `min-width:0` on every item,
   because a bare `1fr` sizes to min-content and one long unbreakable value then scrolls the
   whole page sideways. */
@media(min-width:1800px){
  .wrap--rec{max-width:1680px}
  .rec-layout{grid-template-columns:minmax(0,1fr) 360px;gap:34px}
}
