/* ============================================================
   fleetfax — the dossier system
   The carrier report as a modern document: warm paper canvas,
   ink-first typography, hairline structure. Color is semantic —
   red belongs to the brand mark and to risk, nothing else.
   ============================================================ */

:root {
  /* brand — unified to the official mark red (css/main.css --brand) */
  --red:      #C8102E;
  --red-dk:   #A30D26;
  --red-grad: linear-gradient(180deg, #D31530 0%, #B00E28 100%);
  --red-soft: #FBEDEE;
  --red-line: #F0CBCF;

  /* ink scale on paper */
  --ink:    #16181D;   /* headings, decision values */
  --text:   #3A3D45;   /* body */
  --muted:  #6E7280;
  --faint:  #9BA0AB;
  --bg:     #FFFFFF;   /* panel surface */
  --soft:   #F8F8F7;   /* the page canvas — near-white unified with marketing (was warm paper #F6F6F2; founder v4: white system, cards stay --bg white) */
  --soft-2: #ECECE6;
  --line:   #E4E3DC;   /* warm hairline */
  --line-2: #EFEEE7;

  /* status — calm, professional depths (washes stay quiet; the text carries) */
  --green:    #177E46;
  --green-sf: #EDF6EF;
  --amber:    #8a5e00;
  --amber-sf: #FAF3E3;
  --danger:   #C8102E;
  --danger-sf:#FBEDEE;
  --blue:     #2F6BFF;
  /* FMCSA percentile "alert zone" wash — strong enough to read as a shaded band
     on the percentile track (the old 11% was nearly invisible). Single source so
     the chart band and the legend swatch can never drift apart. */
  --alert-zone: color-mix(in oklab, var(--red) 15%, transparent);
  --alert-zone-edge: color-mix(in oklab, var(--red) 50%, transparent);

  /* radii crisp, shadows near-none: structure comes from rules, not elevation */
  --r-xs: 5px; --r-sm: 7px; --r: 10px; --r-lg: 12px; --r-xl: 16px;
  --sh-xs: none;
  --sh-sm: none;
  --sh:    0 2px 8px rgba(22, 24, 29, .05);
  --sh-lg: 0 12px 34px rgba(22, 24, 29, .12), 0 3px 8px rgba(22, 24, 29, .06);

  /* official fleetfax typography — Inter (sans) + Geist Mono (mono/display) */
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --font-display: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* official brand gradient (matches css/main.css --brand-gradient) */
  --brand-gradient: linear-gradient(135deg, #e6202b 0%, #c8102e 55%, #8e0c20 100%);
  /* Pro brand gradient — graphite-heavy with a single red ember only at the tail
     letters, so the paid surface differentiates from the bright-red free brand
     while staying legible at ~17px (near-black glyphs on white merge).
     Founder-approved VARIANT of the wordmark gradient rule (binding design
     addendum): do not "correct" it back to --brand-gradient. */
  --brand-gradient-pro: linear-gradient(122deg, #23232c 0%, #23232c 56%, #8a1320 92%, #b21420 100%);
}

/* official gradient wordmark */
.ff-wordmark {
  font-family: var(--font-display); font-weight: 600; letter-spacing: -0.04em;
  text-transform: lowercase; color: var(--red-dk);
  background: var(--brand-gradient);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
/* Pro wordmark — a DEEPER red→black gradient than the free brand's lighter red,
   so the paid tier reads as a richer shade of the same identity (keeps the red
   check-mark). Tracking relaxed a touch so the dark tail stays legible at ~17px. */
.ff-wordmark-pro {
  background: linear-gradient(120deg, #b3122a 0%, #7a0c1c 55%, #45070f 100%);
  /* MUST re-declare clip: the `background` shorthand above resets background-clip
     to border-box, which is what turned the wordmark into a filled bar. */
  -webkit-background-clip: text; background-clip: text;
  color: var(--red-dk);
  -webkit-text-fill-color: transparent;
  letter-spacing: -0.015em;
}

/* "beta" pill that follows the wordmark — mirrors the home-page nav badge so the
   carrier header reads "fleetfax beta" too. translateY bottom-aligns the pill on
   the wordmark baseline. */
.ff-beta {
  align-self: center; transform: translateY(2px);
  font-family: var(--mono); font-size: 0.5625rem; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; line-height: 1;
  color: var(--faint); background: none; border: 1px solid var(--line);
  border-radius: 999px; padding: 0.12rem 0.4rem;
}

/* "Pro" pill — the premium-tier marker. Champagne-gold gradient with deep ink
   text: gold is the universal premium signal and pops against the black mark,
   so the paid lockup reads "premium", not "recolored free". */
.ff-pro {
  align-self: flex-end; transform: translateY(0);
  font-family: var(--mono); font-size: 0.5625rem; font-weight: 800;
  letter-spacing: 0.16em; text-transform: uppercase; line-height: 1;
  color: #f6e7e9;
  background: linear-gradient(135deg, #3c0d15 0%, #170609 100%);
  border: 1px solid rgba(255, 255, 255, 0.10); border-radius: 999px; padding: 0.17rem 0.52rem;
  box-shadow: 0 1px 2px rgba(20, 6, 9, 0.25);
}

* { box-sizing: border-box; }
/* Brand-red form controls — the "email me a digest" checkboxes on Alerts +
   Settings rendered OS-default blue, reading as unstyled on a disciplined red
   UI (audit C3). One rule tints every checkbox/radio/range brand red. */
input[type="checkbox"], input[type="radio"], input[type="range"], progress { accent-color: var(--red); }
html, body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--sans); font-size: 14.5px; line-height: 1.55;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  font-feature-settings: "tnum"; /* data product: digits align everywhere */
}

/* ── Shell layout around the canonical marketing nav (founder 2026-07-15) ──
   The static nav.nav (v3/index.html ff-nav region) sits ABOVE the app as a
   flex row; #ff-boot (skeleton) and #root (the app) split the rest and keep
   their internal <main> scroll. The app trees size height:100% (not 100vh)
   so the nav never pushes the report below the viewport. An EMPTY #root
   (React renders null while loading) must not grow, or it would steal half
   the viewport from the skeleton. */
html, body { height: 100%; }
body { display: flex; flex-direction: column; overflow: hidden; }
body > nav.nav { flex: 0 0 auto; }
#ff-boot, #root { flex: 1 1 auto; min-height: 0; }
#root { display: flex; flex-direction: column; }
#root:empty { flex: 0 0 0; }
#ff-boot { min-height: 0; }
/* The app scrolls inside <main>, so a classic scrollbar is carved out of
   main's content box — its centered 1288px column sits half a scrollbar left
   of the nav's (nav is a body-level sibling spanning the full viewport):
   logo 104 vs card 99 at 1440, waitlist CTA protruding past the rail edge.
   Reserving the gutter on BOTH edges keeps main's centering axis identical
   to the nav's; overlay-scrollbar platforms reserve nothing and no-op. */
#ff-boot main, #root main { scrollbar-gutter: stable both-edges; }
/* Signed-in chrome (AppHeader — workspace or signed-in report) renders its own
   full-width bar; the marketing nav yields (app.jsx toggles the body class). */
body.ff-app-chrome > nav.nav { display: none; }
/* Report-side view-transition target: the homepage hero pill (ff-search,
   css/main.css) morphs into the header's compact search pill on carrier
   pages. Scoped HERE (fleetfax.css loads only in the v3 shell) so marketing
   pages keep exactly ONE ff-search element — the hero (main.js contract). */
nav.nav .nav-search { view-transition-name: ff-search; }
/* Report-page header width (founder 2026-07-15): the marketing nav's inner
   container (1200px + 2rem gutters) sat inset from the report column (1288px
   incl. 28px side padding — ProfileBody's heroV "b" wrapper, app.jsx). Match
   them so the logo left-aligns with the report card edge and the right
   cluster with the rail edge. v3-shell-only; marketing pages keep their
   sizing. */
nav.nav .nav-inner { max-width: 1288px; padding-left: 28px; padding-right: 28px; }

h1,h2,h3,h4 { color: var(--ink); font-weight: 650; letter-spacing: -0.015em; margin: 0; line-height: 1.15; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
/* Links are ink, underlined — on a risk product, red is never "click me".
   :where(:not(...)) exempts the canonical nav subtree at ZERO added
   specificity — the nav keeps main.css's marketing styling (no underlines,
   inherited colors) while every report link renders exactly as before. */
a:where(:not(nav.nav a)), .link { color: var(--ink); text-decoration: underline; text-decoration-color: var(--faint);
  text-decoration-thickness: 1px; text-underline-offset: 2.5px; cursor: pointer;
  transition: text-decoration-color .12s; }
a:where(:not(nav.nav a)):hover, .link:hover { text-decoration-color: var(--ink); }

/* monospace eyebrow — slate, never red (red is reserved for risk; the
   .red variant survives as plain emphasis for the fleetfax-read blocks) */
.eyebrow {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.13em; text-transform: uppercase; color: var(--muted);
}
.eyebrow.red { color: var(--ink); }

/* the decision-number tier (UIR-20): bold tabular mono is RESERVED for values
   a broker decides on; everything else renders at body weight */
.num {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-weight: 650; color: var(--ink); letter-spacing: -0.01em;
}

/* subtle gradient ink for big display numbers/wordmark */
.grad-ink {
  background: linear-gradient(150deg, #1A1C20 0%, #4A5260 120%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* ---------- layout helpers ---------- */
.row { display: flex; align-items: center; }
.col { display: flex; flex-direction: column; }
.wrap { flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.between { justify-content: space-between; }
.center { align-items: center; }
.start { align-items: flex-start; }
.g4{gap:4px}.g6{gap:6px}.g8{gap:8px}.g10{gap:10px}.g12{gap:12px}.g14{gap:14px}.g16{gap:16px}.g20{gap:20px}.g24{gap:24px}
.muted{color:var(--muted)} .faint{color:var(--faint)} .ink{color:var(--ink)}
.tiny{font-size:12.5px} .sm{font-size:13.5px}
.nowrap{white-space:nowrap}

/* ---------- card → panel: a ruled region of the document, not a floating box ---------- */
.card {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: none;
}
.card.soft { background: var(--soft); box-shadow: none; }
.card-pad { padding: 22px 24px; }

/* interactive surfaces never inherit the document underline */
a.chip, a.btn, nav a, footer a { text-decoration: none; }
nav a:hover, footer a:hover { text-decoration: underline; text-decoration-color: var(--muted); }

/* ---------- buttons ---------- */
.btn {
  font-family: var(--sans); font-size: 13.5px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  border-radius: 9999px; padding: 8px 15px; border: 1px solid var(--line);  /* design system: pill buttons */
  background: var(--bg); color: var(--ink); box-shadow: none;
  transition: background .12s, border-color .12s, transform .05s;
  white-space: nowrap; text-decoration: none;
}
.btn:hover { background: var(--soft); border-color: var(--soft-2); }
.btn:active { transform: translateY(1px); }
.btn.sm { padding: 5px 10px; font-size: 12.5px; }
.btn.ghost { border-color: transparent; box-shadow: none; background: transparent; }
.btn.ghost:hover { background: var(--soft); }
/* Flat solid brand red — the gradient + inner-highlight treatment read as
   dated (founder, 2026-07-02). Depth comes from the hover/active shade steps,
   not from a bevel. */
.btn.primary {
  background: var(--red); color: #fff; border-color: var(--red);
  box-shadow: 0 1px 2px rgba(0,0,0,.08);
}
.btn.primary:hover { background: var(--red-dk); border-color: var(--red-dk); }
.btn.primary:active { background: #8E0C20; border-color: #8E0C20; box-shadow: none; }
/* Near-black solid — for primary actions that are NOT acquisition (search,
   returning-user login); red stays reserved for the one "Sign up" per view. */
.btn.ink { background: var(--ink); color: #fff; border-color: var(--ink); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.btn.ink:hover { background: #23262d; border-color: #23262d; }
.btn.ink:active { background: #0b0c0e; border-color: #0b0c0e; box-shadow: none; }
.btn.danger { color: var(--red); border-color: var(--red-line); }
.btn.danger:hover { background: var(--danger-sf); border-color: var(--red-line); color: var(--red); }
.icon-btn { width: 34px; height: 34px; padding: 0; justify-content: center; border-radius: var(--r-sm); }

/* ---------- form controls (inputs + selects) ----------
   Shared modern field styling. Selects strip the native chrome
   (appearance:none) and paint a custom chevron so they read as the same
   component family as .btn / .ff-input across every browser, instead of the
   OS default control. */
.ff-input,
.ff-select {
  font-family: var(--sans); font-size: 13.5px; font-weight: 500;
  color: var(--ink); background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 9px 12px; width: 100%; line-height: 1.3;
  box-shadow: var(--sh-xs);
  transition: border-color .12s, box-shadow .12s, background .12s;
  -webkit-appearance: none; appearance: none;
}
.ff-input::placeholder { color: var(--faint); }
.ff-input:hover,
.ff-select:hover { border-color: var(--soft-2); background: var(--soft); }
.ff-input:focus,
.ff-select:focus {
  outline: none; background: var(--bg);
  border-color: #b3122a;
  box-shadow: 0 0 0 3px rgba(179,18,42,.13);
}
/* Custom chevron, inlined SVG so there's no extra asset request. */
.ff-select {
  padding-right: 34px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23697586' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
.ff-select:hover { background-color: var(--soft); }
.ff-select option { color: var(--ink); font-weight: 500; }
.ff-select:disabled,
.ff-input:disabled { opacity: .55; cursor: not-allowed; }
/* A disabled action never reads as clickable — muted + not-allowed, and it
   swallows the click so a gated primary (e.g. an over-budget bulk run) can't be
   pressed. */
.btn:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
/* Compact inline variant — auto width, tighter padding, smaller chevron gutter.
   For controls that sit inline in a row rather than filling a form field. */
.ff-input.sm,
.ff-select.sm { width: auto; padding: 6px 10px; font-size: 13px; }
.ff-select.sm { padding-right: 28px; background-position: right 9px center; }

/* ---------- carrier sourcing (top: lane + filters · map · then results) ------- */
/* TOP band — controls on the left (the working area), map on the right as a
   compact lane preview; collapses to stacked on narrow. */
.ff-sourcing-top {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(330px, 1.1fr);
  gap: 28px; align-items: stretch;
}
@media (max-width: 900px) { .ff-sourcing-top { grid-template-columns: 1fr; gap: 18px; } }

/* ---------- Pro home (PRD-17) ------------------------------------------------
   Two-column shell: the book column + the standing-value right column. On
   narrow viewports the aside stacks BELOW the book (mobile is digest-first:
   banner, then the table, then the cards). */
.ff-home-grid { display: grid; grid-template-columns: minmax(0, 1fr) 296px; gap: 20px; align-items: start; }
@media (max-width: 1080px) { .ff-home-grid { grid-template-columns: 1fr; } }
.ff-home-row:hover { background: var(--soft); }
.ff-home-row:focus-visible { outline: 2px solid var(--red); outline-offset: -2px; }
.ff-home-onramps { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }

/* PRD-20 §7b: change-queue disposition buttons. One gesture each, but three
   weights so 20 alerts read at a glance (founder, 2026-07-09): Reviewed is the
   primary queue-clearing action (subtle ink fill); Move-to-do-not-use is a
   severe state change (quiet at rest, red on hover, ban icon); Watch closer and
   Add a note stay quiet/tertiary. Still no verdict grading — the weights map to
   frequency-of-use and severity-of-consequence, not to a fleetfax judgment. */
.ff-q-act { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600;
  color: var(--ink); background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  padding: 4px 9px; cursor: pointer; line-height: 1; white-space: nowrap; }
.ff-q-act:hover { background: var(--soft); border-color: var(--muted); }
.ff-q-act:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; }
/* Reviewed — the primary, most-used action: a subtle solid fill (ink at low
   alpha) so it reads as filled/primary at rest, distinct from the other chips'
   outline (and from their --soft hover, which it must not be mistaken for). */
.ff-q-act.ff-q-primary { background: rgba(22, 24, 29, .08); border-color: rgba(22, 24, 29, .16); color: var(--ink); }
.ff-q-act.ff-q-primary:hover { background: rgba(22, 24, 29, .14); border-color: rgba(22, 24, 29, .24); }
/* Move to do-not-use — a severe standing change: neutral chip at rest, warns
   red on hover (matches .btn.danger:hover) and carries the ban icon. */
.ff-q-act.ff-q-dnu:hover { background: var(--danger-sf); border-color: var(--red-line); color: var(--red); }
/* Watch closer — quiet/tertiary, the same weight as the note affordance. */
.ff-q-quiet { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600;
  color: var(--muted); background: none; border: none; cursor: pointer; padding: 4px 6px; line-height: 1; white-space: nowrap; }
.ff-q-quiet:hover { color: var(--ink); }
.ff-q-quiet:focus-visible { outline: 2px solid var(--ink); outline-offset: 1px; border-radius: 6px; }
.ff-q-note { font-size: 11.5px; color: var(--muted); background: none; border: none; cursor: pointer;
  padding: 4px 4px; text-decoration: underline; text-underline-offset: 2px; }
.ff-q-note:hover { color: var(--ink); }
/* §7c: the unchanged compressed band toggle */
.ff-unchanged-toggle { width: 100%; text-align: left; background: var(--soft); border: 1px solid var(--line);
  border-radius: 10px; padding: 9px 14px; cursor: pointer; color: var(--muted); font-size: 12.5px; }
.ff-unchanged-toggle:hover { color: var(--ink); }

/* Quick-vet peek (PRD-17 §8.1): a slide-over so a drill-down never leaves the
   scan. Sits above the rail drawer, below the modal layer (z 100). */
.ff-peek-overlay { position: fixed; inset: 0; z-index: 94; background: rgba(11,12,14,.25); }
.ff-peek { position: fixed; top: 0; right: 0; bottom: 0; z-index: 95; width: min(430px, 94vw);
  background: var(--bg); border-left: 1px solid var(--line); box-shadow: var(--sh-md);
  padding: 18px 20px 20px; overflow-y: auto;
  animation: ff-peek-in .16s ease-out; }
@keyframes ff-peek-in { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .ff-peek { animation: none; } }

.ff-sourcing-controls { min-width: 0; }
.ff-sourcing-mapwrap { min-width: 0; display: flex; }

/* Lane area — no frame of its own (the top card is already white). It just
   stretches to the controls' height so the column never leaves dead space: map
   at the top, lane summary pinned to the bottom. */
.ff-map-panel {
  flex: 1; display: flex; flex-direction: column; gap: 14px;
}
.ff-map-foot { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }
.ff-lane-summary {
  display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap;
}
.ff-lane-place {
  display: inline-flex; align-items: center; gap: 7px; min-width: 0;
  font-size: 13px; font-weight: 600; color: var(--ink);
  max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ff-lane-place .ff-lane-dot { position: static; transform: none; box-shadow: none; flex: 0 0 auto; }

/* Lane row: FROM city · swap · TO city. The two inputs flex, the swap sits
   between them and stays vertically centered with the inputs (labels sit inside
   the field via the colored dot, so there's no label row to offset). */
.ff-lane-block { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 9px; }
.ff-city-field { min-width: 0; }
.ff-city-input { width: 100%; padding-left: 30px; font-weight: 600; }
.ff-lane-dot {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 9px; height: 9px; border-radius: 50%; pointer-events: none; z-index: 1;
  box-shadow: 0 0 0 3px var(--bg);
}
.ff-lane-dot-o { background: #334155; }
.ff-lane-dot-d { background: #c8102e; }

/* circular swap button between FROM and TO */
.ff-swapbtn {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); background: var(--bg); color: var(--muted);
  box-shadow: var(--sh-xs); transition: background .12s, color .12s, border-color .12s, transform .12s;
}
.ff-swapbtn:hover:not(:disabled) { background: var(--soft); color: var(--ink); border-color: var(--soft-2); transform: rotate(180deg); }
.ff-swapbtn:disabled { opacity: .4; cursor: not-allowed; }

/* city autocomplete dropdown */
.ff-city-menu {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 8px 24px rgba(16,24,40,.14); padding: 4px; max-height: 248px; overflow-y: auto;
}
.ff-city-opt {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  padding: 7px 9px; border: 0; background: none; border-radius: 7px; font-size: 13px; color: var(--text);
}
.ff-city-opt:hover, .ff-city-opt.on { background: var(--soft); }

/* filter grid — 2-col, fleet (last) spans the full width for its min/max pair */
.ff-filter-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 16px; align-items: start; }
.ff-filter-grid > label:last-child { grid-column: 1 / -1; }
@media (max-width: 560px) { .ff-filter-grid { grid-template-columns: 1fr; } }

/* cargo multiselect: a select-styled button + checkbox popover */
.ff-pickbtn {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; text-align: left; cursor: pointer;
}
.ff-pickbtn.on { border-color: var(--soft-2); background: var(--soft); color: var(--ink); font-weight: 600; }
.ff-cargo-menu {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 40; min-width: 240px;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 8px 24px rgba(16,24,40,.14); padding: 5px; max-height: 280px; overflow-y: auto;
}
.ff-cargo-row {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 6px 9px; border-radius: 7px; font-size: 13px; color: var(--text);
}
.ff-cargo-row:hover { background: var(--soft); }
.ff-cargo-row input { width: 15px; height: 15px; accent-color: var(--red); flex: 0 0 auto; }
.ff-cargo-clear {
  display: block; width: 100%; text-align: left; cursor: pointer; margin-bottom: 3px;
  padding: 6px 9px; border: 0; background: none; border-radius: 7px;
  font-size: 12px; font-weight: 600; color: var(--red);
}
.ff-cargo-clear:hover { background: var(--red-soft); }

.ff-lane-map {
  width: 100%; height: auto; display: block; background: transparent; border: 0; padding: 0;
}
.ff-lane-map path { transition: fill .08s; }

.ff-lane-chip {
  display: inline-flex; align-items: center; justify-content: center; min-width: 40px;
  padding: 4px 11px; border-radius: 999px; font-weight: 700; font-size: 13px;
  font-family: var(--mono); letter-spacing: .04em; border: 1px solid var(--line);
  background: var(--bg); color: var(--faint);
}
.ff-lane-chip.ff-lane-o { color: #334155; border-color: #c7cfd9; background: #f1f4f8; }
.ff-lane-chip.ff-lane-d { color: #c8102e; border-color: var(--red-line); background: var(--red-soft); }

/* filter label */
.ff-flbl { font-size: 10.5px; color: var(--muted); }

/* segmented band selector */
.ff-seg { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.ff-seg-btn {
  font-family: var(--sans); font-size: 12.5px; font-weight: 600; cursor: pointer;
  padding: 6px 11px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--bg); color: var(--muted); box-shadow: var(--sh-xs);
  transition: background .12s, color .12s, border-color .12s;
}
.ff-seg-btn:hover { background: var(--soft); color: var(--ink); }
.ff-seg-btn.on {
  background: var(--ink); color: #fff; border-color: var(--ink);
  box-shadow: 0 1px 2px rgba(11,12,14,.25);
}

/* on/off toggle row */
.ff-toggle-row {
  display: flex; align-items: center; gap: 10px; cursor: pointer; width: 100%;
  background: none; border: 0; padding: 6px 2px; text-align: left;
}
.ff-toggle {
  flex: 0 0 auto; width: 34px; height: 20px; border-radius: 999px;
  background: var(--soft-2); border: 1px solid var(--line); position: relative;
  transition: background .14s, border-color .14s;
}
.ff-toggle.on { background: #334155; border-color: #1f2937; }
.ff-toggle-knob {
  position: absolute; top: 1px; left: 1px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(16,24,40,.25); transition: transform .14s;
}
.ff-toggle.on .ff-toggle-knob { transform: translateX(14px); }

/* tiny inline spinner for live results */
.ff-spin {
  width: 13px; height: 13px; border-radius: 50%; display: inline-block;
  border: 2px solid var(--line); border-top-color: var(--muted); animation: ff-spin .7s linear infinite;
}
@keyframes ff-spin { to { transform: rotate(360deg); } }

/* ranked results — one carrier per FULL-WIDTH row (no horizontal scroll: the
   columns collapse to a stacked block on narrow viewports). */
.ff-src-list { display: flex; flex-direction: column; gap: 8px; }

.ff-src-row {
  display: grid;
  /* full-width rows (map moved to its own band 2026-07-01): the name column
     takes the reclaimed width so long carrier names stop truncating */
  grid-template-columns: minmax(0, 2.8fr) 56px minmax(0, 1.5fr) minmax(0, 1.7fr) max-content;
  gap: 16px; align-items: center;
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 15px 18px;
  background: var(--bg); box-shadow: var(--sh-xs);
  transition: border-color .12s, box-shadow .12s;
}
.ff-src-row:hover { border-color: #d6dae1; box-shadow: 0 2px 8px rgba(16,24,40,.07); }
.ff-src-namelink:hover .ink { color: #c8102e; }
.ff-src-cell-fleet { text-align: right; }
.ff-src-cell-safety { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end; }
/* contact cell — tel / mailto / open-report icon buttons (separate links, so they
   don't nest inside the report link). */
.ff-src-cell-contact { display: flex; align-items: center; gap: 4px; justify-self: end; flex: 0 0 auto; }
.ff-src-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px; color: var(--muted);
  border: 1px solid transparent; transition: background .12s, color .12s, border-color .12s;
}
.ff-src-icon:hover { background: var(--soft); color: var(--ink); border-color: var(--line); }
.ff-src-open:hover { color: #c8102e; }
.ff-src-saved { color: #d98324; }
.ff-src-saved svg { fill: #d98324; }
.ff-src-saved:hover { color: #d98324; }
/* a carrier with a saved note reads as "active" in the brand red */
.ff-src-noted { color: var(--red); }
.ff-src-noted:hover { color: var(--red); border-color: var(--red-line); background: var(--red-soft); }

/* private-note popover */
.ff-note-wrap { display: inline-flex; }
.ff-note-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 50; width: 280px;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: 0 10px 30px rgba(16,24,40,.16); padding: 12px;
}
.ff-note-ta {
  width: 100%; resize: vertical; min-height: 76px; font-family: var(--sans);
  font-size: 13px; line-height: 1.45; color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; background: var(--soft);
}
.ff-note-ta:focus { outline: none; background: var(--bg); border-color: var(--soft-2); box-shadow: 0 0 0 3px rgba(200,16,46,.12); }
.ff-note-ta::placeholder { color: var(--faint); }
/* Stacked block on narrow — name full width, the rest flows beneath; vertical
   scroll only, no horizontal overflow. */
@media (max-width: 820px) {
  .ff-src-row { grid-template-columns: 1fr auto; gap: 7px 14px; }
  .ff-src-cell-name { grid-column: 1 / 2; }
  .ff-src-cell-contact { grid-column: 2 / 3; grid-row: 1; }
  .ff-src-cell-fit { grid-column: 1 / -1; }
  .ff-src-cell-safety { grid-column: 1 / -1; justify-content: flex-start; }
}

/* safety-vs-peers BASIC chip */
.ff-basic-chip {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  font-size: 11.5px; font-weight: 600; line-height: 1;
  padding: 4px 8px; border-radius: 999px; border: 1px solid transparent;
}

/* report-verdict badge on a result card (extremes only) */
.ff-src-verdict {
  display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  font-size: 11px; font-weight: 700; line-height: 1; align-self: flex-start;
  padding: 4px 9px; border-radius: 6px; border: 1px solid transparent;
}
.ff-src-verdict-stop  { color: #B0152A; background: #FCEDEE; border-color: #F3C9CE; }
.ff-src-verdict-clear { color: #475569; background: #F1F4F8; border-color: #D8DEE6; }

/* fit-tier section markers */
.ff-tier-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.ff-tier-strong  { background: #334155; }
.ff-tier-likely  { background: #64748b; }
.ff-tier-weak    { background: #aab2bf; }
.ff-tier-limited { background: var(--line); border: 1px solid #cfd6e0; }

/* ---------- chips / pills ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-size: 12.5px; font-weight: 500; color: var(--text);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; background: var(--bg);
}
.chip.solid { background: var(--soft); border-color: var(--line-2); }
/* Linked-carrier chips carry a long carrier name; let them cap at the container
   and ellipsize the name (instead of forcing horizontal page scroll on narrow). */
.ff-linkchip { max-width: 100%; min-width: 0; overflow: hidden; }
.ff-linkchip .ink { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }
.pill { display:inline-flex; align-items:center; gap:6px; font-size:12.5px; font-weight:600;
  border-radius: 999px; padding: 3px 10px; white-space: nowrap; }
.pill .dot { width:7px; height:7px; border-radius:50%; }
.pill.ok    { background: var(--green-sf);  color: #136A3C; }
.pill.warn  { background: var(--amber-sf);  color: #8A5700; }
.pill.bad   { background: var(--danger-sf); color: var(--red-dk); }
.pill.ok .dot{background:var(--green)} .pill.warn .dot{background:var(--amber)} .pill.bad .dot{background:var(--danger)}
/* tags are quiet metadata labels — ink on paper (red tags meant nothing risky) */
.tag { font-family: var(--mono); font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line); background: var(--soft);
  border-radius: 5px; padding: 2px 6px; font-weight: 500; white-space: nowrap; }
.tag.pro { color: var(--muted); }

.dotc { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }

/* ---------- percentile bar ---------- */
.pbar { position: relative; height: 10px; border-radius: 999px; background: var(--soft-2); overflow: visible; }
.pbar .fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px; }
.pbar .fill.good { background: linear-gradient(90deg,#1FB85C,#15A34A); }
.pbar .fill.warn { background: linear-gradient(90deg,#F2A93B,#E08A00); }
.pbar .fill.bad  { background: var(--red-grad); }
.pbar .alertzone { position: absolute; top: 0; bottom: 0; right: 0; background: var(--alert-zone); border-radius: 0 999px 999px 0; pointer-events: none; }
.pbar .peer { position: absolute; top: -3px; bottom: -3px; width: 2px; background: #0B0C0E; opacity: .55; border-radius: 2px; }
.pbar .thr  { position: absolute; top: -5px; bottom: -5px; width: 0; border-left: 2px dashed var(--alert-zone-edge); }
/* marker-on-track variant: carrier percentile is a dot at its POSITION (lower=better),
   so a 2nd-percentile carrier reads as a dot near the left, never an empty bar. */
.pbar.marker .mark {
  position: absolute; top: 50%; width: 13px; height: 13px; border-radius: 50%;
  transform: translate(-50%, -50%); z-index: 2;
  border: 2px solid var(--bg); box-shadow: 0 0 0 1px rgba(11, 12, 14, .14);
}
.pbar.marker .mark.good { background: #15A34A; }
.pbar.marker .mark.warn { background: #E08A00; }
.pbar.marker .mark.bad  { background: var(--red); }

/* crashes card — 12/12 window comparison, centered severity counts, crash-rate-vs-peers module */
.ff-crash-windows { display: flex; flex-wrap: wrap; gap: 14px; align-items: stretch; }
.ff-crash-win { flex: 1 1 0; min-width: 200px; background: #FBFBF9; border: 1px solid var(--line); border-radius: 10px; padding: 15px 17px; }
/* recent window = brighter white (subtly "the current period"); NO red accent —
   the card frame is neutral, the green/amber delta pill and the red fatal pills
   carry the actual signal, so a same-or-better recent window never reads as worse */
.ff-crash-win-recent { background: var(--bg); }
.ff-crash-bignum { font-size: 30px; font-weight: 800; letter-spacing: -0.03em; color: var(--ink); line-height: 1; }
.ff-crash-delta { font-family: var(--mono); font-size: 13px; font-weight: 700; border-radius: 999px; padding: 4px 11px; white-space: nowrap; border: 1px solid var(--line); }
.ff-crash-counts { display: flex; justify-content: center; flex: 0 0 auto; }
.ff-crash-cell { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 4px 6px; flex: 0 0 120px; }
.ff-crash-cellnum { font-size: 30px; font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
.ff-crash-peer { flex: 1 1 320px; min-width: 300px; }
.ff-sevpill { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--text); background: var(--bg); border: 1px solid var(--line); border-radius: 999px; padding: 2px 9px; }
.ff-sevpill-fatal { border-color: #E7CDD0; background: var(--red-soft); color: var(--red-dk); font-weight: 600; }

/* placeholder imagery */
.ph {
  background:
    repeating-linear-gradient(45deg, var(--soft) 0 9px, var(--soft-2) 9px 10px);
  border: 1px solid var(--line); border-radius: var(--r);
  display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 8px;
  color: var(--muted); font-family: var(--mono); font-size: 11.5px;
}

/* divider */
.hr { height: 1px; background: var(--line); border: 0; }
.vr { width: 1px; background: var(--line); align-self: stretch; }

/* Safety: peer-percentile (BASIC) table beside its "how to read" guide, instead
   of the guide stranded at the page bottom. Stacks (guide drops below the table,
   still attached to the section — never back to the page bottom) once the wide
   6-column BASIC table can no longer share the row without cramping. */
/* summary band: the headline values in equal columns, labels centered beneath
   each, hairline dividers between. Sized to CONTENT (per-stat basis), not a
   rigid 400px — so when only one BASIC is over threshold the band is ~132px,
   not 400px reserving empty space and pushing the "what the data says" read
   onto its own line. Three stats still land at ~396px (visually unchanged). */
.ff-sumstats { display: flex; max-width: 100%; }
.ff-sumstats > div { flex: 1 1 132px; min-width: 0; }
.ff-sumstats > div + div { border-left: 1px solid var(--line); }

.ff-safety-split { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 20px; align-items: stretch; }
@media (max-width: 1080px) { .ff-safety-split { grid-template-columns: 1fr; } }
/* Violations + Roadside side by side; each grows so a lone one spans full width,
   and they wrap to a stack on narrow viewports. */
.ff-safety-pair { display: flex; flex-wrap: wrap; gap: 20px; align-items: start; }
.ff-safety-pair > section { flex: 1 1 420px; min-width: 0; }
/* roadside OOS comparison — a small ruled table reads far cleaner than a strip
   that mixes counts and rates with different denominators. */
.ff-oos { width: 100%; border-collapse: collapse; }
.ff-oos th { text-align: right; font-size: 10.5px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); padding: 0 0 7px; border-bottom: 1px solid var(--line); }
.ff-oos th:first-child { text-align: left; }
.ff-oos td { text-align: right; padding: 9px 0; font-size: 14px; color: var(--text);
  font-variant-numeric: tabular-nums; border-bottom: 1px solid var(--line-2); }
.ff-oos td:first-child { text-align: left; font-weight: 650; color: var(--ink); }
.ff-oos tr:last-child td { border-bottom: none; }
.ff-oos td.oos-bad { color: var(--red); font-weight: 700; }
.ff-oos td.oos-natl { color: var(--faint); }
/* How-to guide capped to the BASIC table's height: the scroll layer is absolute so
   it contributes no height (the table drives the row), then scrolls with a bottom
   fade when its own content is taller. */
.ff-howto { position: relative; overflow: hidden; }
.ff-howto-scroll {
  position: absolute; inset: 0; overflow-y: auto; padding: 18px 20px 20px;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent);
}
@media (max-width: 1080px) {
  .ff-howto { position: static; overflow: visible; }
  .ff-howto-scroll { position: static; overflow: visible; padding: 18px 20px;
    -webkit-mask-image: none; mask-image: none; }
}
/* vertical dividers become stray lines once flex zones wrap to a stack — hide on narrow */
@media (max-width: 760px) { .vr { display: none; } }

/* document tabs — quiet text items on the canvas; the active one is ink with a
   2px ink underline (no folder chrome, no hue accents — section identity comes
   from each tab's icon and its content's section heads) */
/* Segmented control: a track with evenly-spaced tabs (flex:1), the active one a
   raised white pill. Reads unmistakably as a switcher (the old faint-label strip
   didn't). */
.ftabs {
  /* space-between, NOT equal-width segments: tabs are content-width so the gap
     BETWEEN the labels is even (equal-width segments padded short labels out and
     left uneven spacing between the actual text). overflow:visible so the last
     tab's notification dot isn't cropped. */
  display: flex; justify-content: space-between; background: #f1efe9; border-radius: 11px;
  padding: 4px 6px; overflow: visible; position: relative;
}
/* Single sliding indicator: one white pill that glides between tabs on selection
   (the active tab's own background was instant). JS positions it over the active
   tab; the transition does the slide. z-index:0 keeps it behind the tab content. */
.ff-tabpill {
  position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none;
  background: #fff; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.12);
  transition: transform .34s cubic-bezier(.32,.72,0,1), width .34s cubic-bezier(.32,.72,0,1);
}
@media (prefers-reduced-motion: reduce) { .ff-tabpill { transition: none; } }
.ftabs::-webkit-scrollbar { display: none; }

/* ── Sticky carrier header ───────────────────────────────────────────────────
   Two states. EXPANDED (default): the tab strip is a rounded gray pill sitting
   on the page canvas, just under the hero. STUCK (.is-stuck, set once the hero
   scrolls past): the compact identity row + tabs fuse into one flat app-bar —
   a single bordered, rounded panel whose tab strip is full-bleed (square, edge
   to edge). The old design nested the rounded pill inside the soft sticky box,
   so its top corners clipped against the compact bar's divider and revealed the
   canvas behind them (the "corners aren't fully round" artifact). Full-bleed =
   no nested rounded corners to clip. The outer .ff-stickyhead keeps the soft
   canvas + a constant 12px top gap so the panel floats cleanly below the nav
   and the tabs never bob at the boundary. (founder 2026-06-29) */
.ff-stickyhead { position: sticky; top: 0; z-index: 20; background: var(--soft); padding-top: 12px; margin-top: 4px; }
.ff-stickyhead-inner.is-stuck {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; box-shadow: 0 8px 20px -14px rgba(11, 12, 14, .30);
}
/* CompactHero carries only ~2px side padding of its own; inset it from the panel
   edge. Vertical padding stays with CompactHero's own row. */
.ff-stickyhead-inner.is-stuck .ff-compactbar { padding-left: 14px; padding-right: 14px; }
/* full-bleed tab strip: drop the pill radius, hairline-separate it from the row.
   bg/padding inherit from .ftabs so the tabs and sliding pill don't move. */
.ff-stickyhead-inner.is-stuck .ftabs { border-radius: 0; border-top: 1px solid var(--line); }

/* ── Copy-link affordance on section headers ─────────────────────────────────
   A small link icon by a section title. Quiet until the section card (or its
   header) is hovered, then one click copies a deep link to that card. Always on
   for touch (no hover) and keyboard focus; flips green on copy. (founder 2026-06-29) */
.ff-copylink {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; flex: 0 0 auto;
  border: 1px solid transparent; border-radius: 6px; background: transparent;
  color: var(--faint); cursor: pointer; opacity: 0;
  transition: opacity .12s ease, color .12s ease, background .12s ease, border-color .12s ease;
}
.card:hover .ff-copylink, .ff-sechead:hover .ff-copylink, .ff-copylink:focus-visible { opacity: 1; }
.ff-copylink:hover { color: var(--ink); background: var(--soft); border-color: var(--line); }
.ff-copylink.done { opacity: 1; color: var(--green); border-color: #CDE9D5; background: var(--green-sf); }
@media (hover: none) { .ff-copylink { opacity: 1; } }

.ftab {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  white-space: nowrap; cursor: pointer;
  font-family: var(--sans); font-size: 13.5px; font-weight: 600; color: var(--muted);
  /* roomier pills so the strip doesn't read sparse when space-between spreads five
     short labels across the full width */
  padding: 9px 22px; border: none; background: transparent;
  position: relative; z-index: 1; border-radius: 8px;
  transition: color .15s;
}
/* tab labels: full name by default; the short alias (when a tab has one) is
   phone-only — see the mobile block below. */
.ff-tab-short { display: none; }

/* responsive header: drop the keyboard hint / help on narrow so the search fits */
@media (max-width: 640px) { .ff-kbd { display: none !important; } }
@media (max-width: 480px) { .ff-help { display: none !important; } }

/* header grid: logo | search | nav on one row. On narrow screens the centered
   560px search column would shove the DOT pill and submit button into the nav
   links, so the search drops to its own full-width second row instead. */
.ff-header-grid {
  display: grid; grid-template-columns: 1fr minmax(0, 560px) 1fr;
  grid-template-areas: "logo search nav";
  align-items: center; gap: 16px;
  max-width: 1240px; margin: 0 auto; padding: 11px 28px; width: 100%;
}
.ff-header-logo { grid-area: logo; justify-self: start; }
/* The report/boot header wordmark matches the canonical marketing nav
   (.nav-brand-text in css/main.css): Geist Mono 600, not the .ff-wordmark
   default 700 — so the report brand never reads heavier than every other
   page's (wordmark hard rule). Scoped to the report header (both the React
   .ff-header-logo button and the #ff-boot .ff-header-logo div carry the same
   .ff-wordmark span), so the boot→React handoff never flashes a weight shift. */
.ff-header-logo .ff-wordmark { font-weight: 600; }
.ff-header-search { grid-area: search; }
.ff-header-nav { grid-area: nav; justify-self: end; }
/* In the single-row band where the centered search column is squeezed by the
   four nav links (before it drops to its own row at 720px), the placeholder
   truncates mid-word and reads as broken. Hide it there — the icon + Search
   button still make the box obviously a search (founder 2026-06-30). */
@media (min-width: 721px) and (max-width: 940px) {
  .ff-csearch-input::placeholder { color: transparent; }
}
@media (max-width: 720px) {
  .ff-header-grid {
    grid-template-columns: auto 1fr;
    grid-template-areas: "logo nav" "search search";
    gap: 8px 12px; padding: 10px 14px;
  }
  /* On the full-width search row the long "Search by USDOT, MC, name, phone,
     or email" placeholder still overruns the input at phone widths (~390px)
     and hard-clipped mid-word against the Search button. Truncate it at an
     ellipsis instead; the input's own text gets the same treatment when
     unfocused, which reads better than a raw clip. */
  .ff-csearch-input { text-overflow: ellipsis; }
  .ff-csearch-input::placeholder { text-overflow: ellipsis; }
  /* P0 mobile fix (audit §4.2): the anon carrier/sign-in header rendered the
     full desktop nav at 390px, so the secondary text links pushed "Try Pro"
     off the right edge. Collapse the text links; keep the persistent primary
     CTA (Sign in / Try Pro are <button class="btn">, untouched by a.sm). */
  .ff-header-nav a.sm { display: none; }
  .ff-header-nav { gap: 8px !important; }
  /* These three links are the report's only primary nav on a phone. At ~13px
     they were ~21px tall — too small to tap. Give each a 40px touch target;
     the header row grows to match, which is fine on mobile. */
  .ff-header-nav a { display: inline-flex; align-items: center; min-height: 40px; }
  /* In-card controls that are mouse-precise but finger-small on a phone:
     the copy-USDOT/MC icon buttons (were 24px), Share (25px), and the freshness
     "refresh" link (15px). Expand the hit area on narrow screens only — the
     icon/label stay the same size, just centered in a bigger tap zone. */
  .ff-copy {
    min-width: 38px; min-height: 38px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .btn.sm[data-ff-share] { min-height: 40px; }
  .link[role="button"] { display: inline-flex; align-items: center; min-height: 36px; }
}

/* (Removed the narrow-screen right-edge scroll shadow: with flex:1 segments the
   strip no longer scrolls, and that gradient was painting over the segmented
   track on phones, making the tabs look like loose labels on the page.) */
.ftab:hover { color: var(--ink); }
.ftab .tdot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ftab[aria-selected="true"] { color: var(--ink); font-weight: 680; }   /* the sliding .ff-tabpill paints the white background */
.ftab[aria-selected="true"] svg { color: var(--red) !important; }
/* Notification-style alert dot: a tab carrying unseen flagged findings (Safety,
   Authority...) wears a small red dot at the label's top-right corner (like an app
   icon badge). It clears the first time the user opens that tab (via the strip OR a
   flag deep-link) — see app.jsx visited state. The label wrapper is its anchor so it
   tracks the centered text, not the wide segment's far edge. */
.ff-tab-label { position: relative; display: inline-flex; align-items: center; }
/* Sits in the tab's right padding with breathing room off the label text (content-width
   tabs mean there's room now); not so far it spills past the last tab's edge. */
.ff-tabdot { position: absolute; top: -1px; right: -12px; width: 6px; height: 6px; border-radius: 50%; background: var(--red); }
/* Suppress the persistent mouse-click focus ring on tabs (the stray border that
   appeared after clicking); keep a real, intentional ring for keyboard users. */
.ftab:focus { outline: none; }
.ftab:focus-visible { outline: 2px solid color-mix(in oklab, var(--ink) 45%, transparent); outline-offset: 1px; border-radius: var(--r-xs); }

/* DOT / MC deep-link to the official FMCSA SAFER snapshot — subtle hover underline
   so the clickability reads without shouting "link" in the identifier row. */
.ff-extlink { text-decoration: none; cursor: pointer; }
.ff-extlink:hover { text-decoration: underline; text-underline-offset: 2px; }

/* equipment unit table — 10 columns never fit a phone; scroll it horizontally
   inside its own track instead of blowing out the whole page width. */
.eq-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  /* let the table keep its natural column widths and scroll, not crush */
  margin: 0 -2px var(--s-5, 20px);
}
.eq-table-scroll .eq-table { margin-bottom: 0; min-width: 760px; }
/* faint right-edge cue that there's more to scroll */
@media (max-width: 760px) {
  .eq-table-scroll {
    background:
      linear-gradient(90deg, var(--bg) 30%, transparent),
      linear-gradient(90deg, transparent, var(--bg) 70%) 100% 0,
      radial-gradient(farthest-side at 0 50%, rgba(11,12,14,.10), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(11,12,14,.10), transparent) 100% 0;
    background-repeat: no-repeat;
    background-size: 24px 100%, 24px 100%, 12px 100%, 12px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}

/* Horizontal-scroll affordance for the book tables (All carriers / Watchlist /
   Do-not-use / home book): a faint edge shadow that shows only on the side that
   has more content to scroll to, so the ~980px grid reads as swipeable instead
   of arbitrarily cut off. Same four-layer technique as .eq-table-scroll, but set
   via background-IMAGE longhands (not the `background` shorthand) so the card's
   own `background-color: var(--bg)` survives — otherwise the card's middle would
   go transparent onto the page canvas. The two `local` cover layers travel with
   the content and hide the shadow on the side that is fully scrolled; the two
   `scroll` shadow layers are pinned to the viewport edges. */
.ff-scroll-x {
  background-image:
    linear-gradient(90deg, var(--bg) 30%, rgba(255,255,255,0)),
    linear-gradient(90deg, rgba(255,255,255,0), var(--bg) 70%),
    radial-gradient(farthest-side at 0 50%, rgba(11,12,14,.12), transparent),
    radial-gradient(farthest-side at 100% 50%, rgba(11,12,14,.12), transparent);
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-repeat: no-repeat;
  background-size: 28px 100%, 28px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* Summary stat clusters (Safety summary + inspection rows) sit in flex columns
   that are `flex:0 0 auto` for the desktop 2-up layout. shrink:0 stops the inner
   wrapped stat row from ever wrapping on a phone, so the last stat clips off the
   right edge. On narrow, let the column take the full width and shrink so its
   `.row.wrap` of stats wraps cleanly. */
@media (max-width: 640px) {
  .ff-statcol { flex: 1 1 100% !important; min-width: 0 !important; width: 100%; }
}

/* Compact (scrolled) hero: on a phone the status pills crowd the verdict label
   and Save button off the edge. Drop the secondary pills — the verdict + Save
   are the load-bearing controls; the pills repeat what the full hero shows. */
@media (max-width: 640px) { .cmpt-pill, .cmpt-dot, .cmpt-concern { display: none !important; } }
/* keep the compact-bar call button as an icon-only tap target on narrow */
@media (max-width: 520px) { .cmpt-calltext { display: none !important; } }

/* Home freshness receipt + its first-run explainer: a `row between center`
   where the left sentence wraps to 4-5 lines on a phone while the right toggle
   ("What was checked" / "Got it") stays vertically centered against it, so the
   toggle reads as jammed mid-paragraph. On a phone, stack them — the wrapped
   sentence, then the toggle beneath it, both left-aligned. */
@media (max-width: 640px) {
  .ff-receipt-stack { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* contact copy buttons — quiet by default, lift on hover (always visible so a
   trackpad/touch user can reach them without a hover state). */
.ff-copy:hover { background: var(--soft) !important; color: var(--ink) !important; }
.ff-contact .ff-copy { opacity: .55; transition: opacity .12s; }
.ff-contact:hover .ff-copy, .ff-copy:focus-visible { opacity: 1; }

/* ============================================================
   dossier furniture — letterhead, verdict, vitals, document bar
   ============================================================ */

/* the fleetfax signature: a 2px brand rule across the very top of the page —
   the one place red is purely brand. Applied to the header element. */
.ff-spine { border-top: none; }  /* red top bar removed (dated look, founder 2026-07-03) */

/* document caption row above the letterhead: what this page IS + when its
   data was pulled. The screenshot-recognizable furniture. */
.ff-doccap {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 0 2px 10px;
}
.ff-doccap .ff-doclabel {
  font-family: var(--mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted);
  display: inline-flex; align-items: center; gap: 8px;
}
.ff-doccap .ff-doclabel::after {
  content: ""; height: 1px; width: 36px; background: var(--line); display: inline-block;
}
.ff-doccap .ff-doclabel { white-space: nowrap; }
@media (max-width: 640px) {
  .ff-doccap { align-items: flex-start; }
  .ff-doccap .ff-doclabel::after { display: none; }
}

/* letterhead: identity block at the top of the dossier */
.ff-letterhead h1 {
  font-size: 30px; font-weight: 680; letter-spacing: -0.022em; line-height: 1.08;
  text-wrap: balance;
}
@media (max-width: 640px) { .ff-letterhead h1 { font-size: 24px; } }

/* the verdict band — the page's one large color statement */
.ff-verdict { border-radius: var(--r); padding: 14px 16px; }
.ff-verdict .ff-verdict-label { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }

/* ── Watch this carrier capture (SEO-lander fold) ────────────────────────────
   The in-flow module (copy left, email field right) and its shared field, plus
   the button popover's field. No accent left-border; the black-pill CTA is
   .btn.ink. Stacks to a single column on phones (no absolute overflow). */
.ff-watch { position: relative; margin-top: 16px; padding: 16px 20px; }
.ff-watch-x { position: absolute; top: 10px; right: 10px; border: 0; background: transparent;
  cursor: pointer; color: var(--muted); padding: 5px; border-radius: 7px; line-height: 0; }
.ff-watch-x:hover { background: var(--soft-2); color: var(--ink); }
.ff-watch-in { display: flex; gap: 24px; align-items: center; padding-right: 22px; }
.ff-watch-copy { flex: 1; min-width: 0; }
/* One lead sentence, no headline stack (copy revision 2026-07-16). */
.ff-watch-lead { font-size: 14.5px; line-height: 1.5; color: var(--text); max-width: 56ch; }
.ff-watch-lead b { color: var(--ink); font-weight: 650; }
/* .ff-watch-h remains for the popover headline. */
.ff-watch-h { font-size: 18px; font-weight: 650; letter-spacing: -0.01em; color: var(--ink); margin: 7px 0 6px; }
.ff-watch-form { flex: 0 0 auto; width: 296px; }
.ff-watch-field { display: flex; align-items: center; gap: 6px; background: var(--bg);
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 4px 4px 14px; }
.ff-watch-field input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font-family: inherit; font-size: 13.5px; color: var(--ink); }
.ff-watch-field .btn { flex: 0 0 auto; }
.ff-watch-fine { font-size: 12px; color: var(--muted); margin-top: 9px; padding-left: 2px; line-height: 1.45; }
.ff-watch-fine b { color: var(--text); font-weight: 600; }
@media (max-width: 720px) {
  .ff-watch-in { flex-direction: column; align-items: stretch; gap: 15px; padding-right: 0; }
  .ff-watch-lead { padding-right: 26px; } /* clear the dismiss ✕ */
  .ff-watch-form { width: 100%; }
  .ff-watch-field { flex-direction: column; border: 0; background: transparent; padding: 0; gap: 9px; }
  .ff-watch-field input { width: 100%; border: 1px solid var(--line); border-radius: 999px; padding: 11px 15px; font-size: 15px; }
  .ff-watch-field .btn { width: 100%; justify-content: center; padding: 11px 0; }
}

/* vitals strip: the dossier's key-value summary row. Equal columns with
   hairline dividers; label over value over context. */
.ff-vitals {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  border-top: 1px solid var(--line); margin-top: 16px; padding-top: 14px;
}
.ff-vitals > div {
  min-width: 0; padding: 2px 18px 0 0; display: flex; flex-direction: column; gap: 3px;
}
.ff-vitals > div + div { border-left: 1px solid var(--line-2); padding-left: 18px; }
.ff-vitals .ff-vital-v { font-size: 19px; line-height: 1.25; overflow-wrap: break-word; }
/* Long unwrappable words step the face down so the value never crosses the
   column divider (hero.jsx Vital sets the class by longest word: >=11ch long,
   >=14ch xlong — "Satisfactory" overflowed at 19px, founder 2026-07-16).
   overflow-wrap above is the last-resort guard for anything longer still. */
.ff-vitals .ff-vital-v-long { font-size: 16px; }
.ff-vitals .ff-vital-v-xlong { font-size: 13.5px; line-height: 1.35; }
.ff-vitals .ff-vital-sub { font-size: 11.5px; color: var(--muted); line-height: 1.35; }
/* Clickable at-a-glance vitals: each deep-links to its full section. Quiet by
   default (just the small arrow in the eyebrow), with a clear hover/focus cue. */
.ff-vital-link { cursor: pointer; }
.ff-vital-arrow { color: var(--faint); transition: color .12s, transform .12s; }
.ff-vital-link:hover .ff-vital-arrow { color: var(--muted); transform: translateX(2px); }
.ff-vital-link:hover .eyebrow { color: var(--ink); }
.ff-vital-link:focus { outline: none; }
.ff-vital-link:focus-visible { outline: 2px solid color-mix(in oklab, var(--ink) 40%, transparent); outline-offset: 3px; border-radius: 6px; }
@media (max-width: 640px) {
  .ff-vitals { grid-template-columns: 1fr 1fr; row-gap: 14px; }
  /* in a 2-col wrap, only the second column keeps its divider */
  .ff-vitals > div + div { border-left: none; padding-left: 0; }
  .ff-vitals > div:nth-child(2n) { border-left: 1px solid var(--line-2); padding-left: 16px; }
}

/* section heads read as document headings: title + hairline rule extending right */
.ff-shead-rule { flex: 1; height: 1px; background: var(--line-2); min-width: 24px; }

/* ── hero variant furniture (preview: ?hero=a|b|c) ───────────────────────── */

/* A · contact panel docked top-right of the letterhead, ruled off from the
   identity column. On narrow screens it slides under the verdict, full width. */
.ff-hero-contact {
  border-left: 1px solid var(--line-2);
  padding-left: 22px;
  align-self: stretch;
  display: flex; flex-direction: column; justify-content: center;
}
@media (max-width: 860px) {
  .ff-hero-contact { border-left: none; padding-left: 0; flex: 1 1 100% !important; }
}

/* B · the action rail: sticks while the report scrolls. Hidden on narrow
   viewports — the bottom action bar takes over there. */
.ff-rail {
  /* min-width:0 + max-width beat the flex min-content default — a long
     unbreakable value wraps inside the rail, never widens it. 312px so full
     contact lines (email/address) fit without truncating. */
  flex: 0 0 312px; width: 312px; max-width: 312px; min-width: 0;
  position: sticky; top: 12px;
  align-self: flex-start;
}
@media (max-width: 1080px) { .ff-rail { display: none; } }

/* Mobile Ask entry — the phones' door to the grounded assistant that lives in
   the desktop .ff-rail. Its visibility is the STRICT INVERSE of .ff-rail: hidden
   by default (desktop, where the rail owns the panel), shown only <=1080px (the
   same breakpoint that hides the rail). The two never overlap, so RailAsk can
   never be visible or focusable twice on one page. A quiet, full-width house
   pill — not red-dominant; only the sparkle mark carries the accent. */
.ff-ask-m { display: none; }
@media (max-width: 1080px) { .ff-ask-m { display: block; margin: 14px 0 2px; } }
.ff-ask-m-toggle {
  display: flex; align-items: center; gap: 9px; width: 100%;
  min-height: 46px; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--bg); box-shadow: var(--sh-sm);
  color: var(--ink); font: 600 13.5px/1.2 var(--sans); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ff-ask-m-toggle:hover { border-color: var(--line-2); }
.ff-ask-m-toggle[aria-expanded="true"] { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.ff-ask-m-chev { color: var(--muted); transition: transform .18s ease; flex: 0 0 auto; }
.ff-ask-m-body {
  border: 1px solid var(--line); border-top: none;
  border-bottom-left-radius: 12px; border-bottom-right-radius: 12px;
  background: var(--soft); padding: 12px 14px 14px;
}
@media (prefers-reduced-motion: reduce) { .ff-ask-m-chev { transition: none; } }
/* The explanatory reads/tips live in the PERSISTENT bar on every device — the
   sticky rail on desktop, the bottom dock on mobile — so the inline body copy is
   never shown. Kept in the markup as a no-JS fallback only (founder 2026-06-13:
   informational, unchanging content belongs in the persistent column). */
.ff-help-inbody { display: none !important; }
/* The Overview Contact card: in variant B the rail carries contact on desktop,
   so hide this card >1080px; <=1080px the rail is gone, so it shows and keeps
   the carrier's phone/email/address reachable as readable text (the mobile dock
   has actions only). In variant A the card has no class and always shows. */
@media (min-width: 1081px) { .ff-contact-railable { display: none !important; } }
/* B · the persistent bar, mobile form: a fixed bottom dock. Stacks the
   scroll-aware contextual toggle/body (the understanding layer the desktop rail
   carries) above the contact quick-actions. */
.ff-actionbar {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  flex-direction: column;
  padding: 8px 10px calc(8px + env(safe-area-inset-bottom, 0px));
  background: color-mix(in oklab, var(--bg) 92%, transparent);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  gap: 8px;
}
.ff-actionbar-btns { display: flex; gap: 8px; }
/* min-width:0 so 'USDOT'+icon never clips at 375px; min-height:44 for a proper
   touch target; tighter side padding to fit three buttons on a phone. */
.ff-actionbar-btns .btn { flex: 1; justify-content: center; min-width: 0; min-height: 44px; padding-left: 8px; padding-right: 8px; }
/* scroll-aware contextual toggle + expanded body */
.ff-mobctx-toggle {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 8px 11px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--soft); color: var(--ink);
  font-family: var(--sans); font-size: 12.5px; font-weight: 600;
}
.ff-mobctx-body {
  max-height: 42vh; overflow-y: auto;
  padding: 13px 13px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--bg);
}
@media (max-width: 1080px) { .ff-actionbar { display: flex; } }
/* The mobile bottom dock was removed (founder 2026-06-23), so no fixed bar to
   clear — just a normal bottom gutter, and the feedback bubble sits low again. */
@media (max-width: 1080px) {
  main.grow { padding-bottom: calc(28px + env(safe-area-inset-bottom, 0px)); }
  .feedback-button { bottom: calc(20px + env(safe-area-inset-bottom, 0px)) !important; }
}
/* Short landscape (e.g. a phone turned sideways, ~393px tall): drop the
   redundant compact sticky bar — it only re-states the hero's name/USDOT/verdict
   — so the tab strip and a usable slice of report content stay on screen. */
@media (max-height: 500px) and (orientation: landscape) {
  .ff-compactbar { display: none !important; }
}

/* ── AI summary card: the one surface allowed to shimmer ─────────────────────
   A slowly rotating conic-gradient border (the "AI glow") in a muted
   spectrum — distinctive without fighting the semantic palette (red still
   means risk; this halo means "generated"). Honors reduced-motion. */
@property --ff-ai-angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
.ff-ai-card {
  border: 1px solid transparent !important;
  background:
    linear-gradient(var(--bg), var(--bg)) padding-box,
    conic-gradient(from var(--ff-ai-angle),
      #6B8FE8, #8E7BE0, #C76FA8, #D9A05B, #7FB07A, #6B8FE8) border-box;
  animation: ff-ai-spin 7s linear infinite;
  box-shadow: 0 0 0 4px color-mix(in oklab, #8E7BE0 7%, transparent);
}
@keyframes ff-ai-spin { to { --ff-ai-angle: 360deg; } }
@media (prefers-reduced-motion: reduce) { .ff-ai-card { animation: none; } }
/* the AI mark picks up the same spectrum */
.ff-ai-mark { color: var(--red); }
/* the rail's AI button: big, obvious, wearing the glow */
.ff-ai-btn {
  width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--sans); font-size: 13.5px; font-weight: 600; color: var(--ink);
  padding: 11px 14px; cursor: pointer; border-radius: var(--r-sm);
  border: 1px solid transparent;
  background:
    linear-gradient(var(--bg), var(--bg)) padding-box,
    conic-gradient(from var(--ff-ai-angle),
      #6B8FE8, #8E7BE0, #C76FA8, #D9A05B, #7FB07A, #6B8FE8) border-box;
  animation: ff-ai-spin 7s linear infinite;
  box-shadow: 0 0 0 3px color-mix(in oklab, #8E7BE0 7%, transparent);
  transition: box-shadow .15s;
}
.ff-ai-btn:hover { box-shadow: 0 0 0 5px color-mix(in oklab, #8E7BE0 12%, transparent); }
.ff-ai-btn:disabled { cursor: default; opacity: .75; }
@media (prefers-reduced-motion: reduce) { .ff-ai-btn { animation: none; } }
/* the rail can outgrow short viewports once a summary is open — scroll inside */
.ff-rail { max-height: calc(100vh - 24px); overflow-y: auto; }

/* rail contextual tip eases in when its section scrolls into view */
.ff-railtip { animation: ff-tip-in .22s ease-out; }
@keyframes ff-tip-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* C · cockpit band: contact cell + vitals in one ruled region */
.ff-cockpit {
  display: flex; align-items: stretch; gap: 22px;
  border-top: 1px solid var(--line); margin-top: 16px; padding-top: 14px;
}
.ff-cockpit-contact { flex: 0 1 300px; min-width: 250px; border-right: 1px solid var(--line-2); padding-right: 22px; }
.ff-cockpit-vitals { flex: 1; border-top: none; margin-top: 0; padding-top: 0; }
@media (max-width: 860px) {
  .ff-cockpit { flex-direction: column; }
  .ff-cockpit-contact { border-right: none; padding-right: 0; flex: 1 1 auto; }
}

/* Overview grid: full-width ruled sections, with Contact + Address pairing up
   half-width on desktop; one column on narrow screens */
/* minmax(0,1fr), not bare 1fr: a bare 1fr is minmax(auto,1fr), whose floor is
   the widest item's min-content (~420px here), so on a phone the track refused
   to shrink and every card overflowed the viewport. minmax(0,…) lets tracks
   shrink to the container so card content can go fluid. */
.ff-ovgrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
@media (max-width: 880px) { .ff-ovgrid { grid-template-columns: minmax(0, 1fr); } }
/* Variant B (rail) desktop: the Contact card is hidden (the rail carries it),
   which would orphan its grid partner (Address check) with an empty cell beside
   it. Let Address span full width and split its body into details | map so it
   fills the row instead of leaving dead space. */
@media (min-width: 1081px) {
  .ff-ovgrid-b #ff-address { grid-column: 1 / -1; }
  .ff-ovgrid-b #ff-address .ff-addr-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; align-items: stretch; }
}

/* Address-check map: the embed is lazy-mounted, so before/while it loads the
   area was a bare white block against the warm page (read as a "white square").
   Give the container + its lazy placeholder the warm-gray fill + rounded frame
   so the loading state looks intentional, not broken. */
.ff-addr-map, .ff-addr-map > div { background: var(--soft); border-radius: 12px; }
.ff-addr-map > div { overflow: hidden; min-height: 300px; }
.ff-addr-map iframe { background: var(--soft); }

/* ── v4 shell responsive (the Rail + account/explorer chrome) ────────────────
   ≤768px the 248px sidebar Rail becomes a horizontally-scrollable top bar so
   the content pane keeps the full viewport width on phones/portrait tablets.
   The Rail is inline-styled in app.jsx (flex-basis, borders, direction), so
   these overrides need !important to win. Dark-safe: the Rail only exists when
   the accounts surface answers the /me probe — none of this can affect the
   anonymous prod page. */
/* Narrow viewports: the rail becomes a slide-in DRAWER behind a hamburger (in
   the header), so the full nav + labels + account block stay intact with no
   horizontal overflow. The content column takes the full width (the fixed rail
   leaves the flow). */
/* Plan chip on the rail account card: the ONE place the plan is named. FREE is
   quiet furniture; PRO/TEAM carry the brand gradient. Never on the wordmark. */
.ff-plan-chip {
  font-family: var(--mono); font-size: 10px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  padding: 2px 9px; border-radius: 999px;
  background: var(--soft); color: var(--muted); border: 1px solid var(--line);
}
.ff-plan-chip-paid {
  background: var(--red);
  color: #fff; border: 1px solid transparent;
}

/* Anonymous carrier-report watch nudge: give the feedback pill room on phones
   (it would cover body text at 390px; the nudge is desktop furniture). */
@media (max-width: 700px) { .ff-watch-nudge { display: none; } }
/* Suppress the floating anonymous watch nudge where the contact rail is visible
   (>=1081px) — the rail now docks it inline (hero.jsx). Between 701-1080px the
   rail is hidden, so the floating card stays as the only nudge. */
@media (min-width: 1081px) { .ff-watch-nudge { display: none; } }

/* Pro-home "changes" digest: one-line ellipsis on desktop, but on a phone the
   date column squeezed the reason to "Federa…"/"BIPD li…". Let it wrap to two
   lines on mobile instead of hard-truncating (audit P1·11). */
.ff-digest-sum { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 640px) {
  .ff-digest-sum { white-space: normal; text-overflow: clip; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
}

.ff-hamburger { display: none; }
@media (max-width: 900px) {
  .ff-rail {
    position: fixed !important; top: 0; left: 0; height: 100vh !important;
    width: 268px !important; flex-basis: 268px !important; z-index: 60;
    transform: translateX(-100%); transition: transform 0.22s ease;
    box-shadow: 2px 0 22px rgba(10, 10, 12, 0.20);
  }
  .ff-rail.ff-rail-open { transform: translateX(0); }
  .ff-rail-overlay { position: fixed; inset: 0; background: rgba(10, 10, 12, 0.42); z-index: 55; }
  .ff-hamburger { display: inline-flex !important; }
}

/* ── Airtable/Stripe-style workspace shell (founder 2026-07-03) ──────────────
   One full-width app bar ABOVE the sidebar (the old layout nested the header in
   the column to the RIGHT of the rail, so it stopped at the rail's edge — the
   inconsistency the founder flagged). .ff-appside is the workspace nav column,
   decoupled from the report's sticky .ff-rail so the two never share rules. */
.ff-appbar {
  flex: 0 0 auto;
  display: grid; grid-template-columns: 1fr minmax(0, 520px) 1fr;
  align-items: center; gap: 16px; height: 58px; padding: 0 16px;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
.ff-appbar-left { display: flex; align-items: center; gap: 8px; justify-self: start; min-width: 0; }
.ff-appbar-search { justify-self: center; width: 100%; display: flex; justify-content: center; min-width: 0; }
.ff-appbar-right { display: flex; align-items: center; gap: 2px; justify-self: end; }
.ff-appbar-icon {
  width: 36px; height: 36px; border-radius: 8px; border: none; background: transparent;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  color: var(--muted); transition: background .12s ease, color .12s ease;
}
.ff-appbar-icon:hover { background: var(--soft); color: var(--ink); }
.ff-appbar-brand { display: inline-flex; align-items: center; }
.ff-appbar-avatar {
  width: 32px; height: 32px; margin-left: 6px; border-radius: 50%; border: none; cursor: pointer;
  background: linear-gradient(135deg, #2b3040, #141821); color: #fff;
  font-weight: 700; font-size: 13px; font-family: var(--sans);
  display: inline-flex; align-items: center; justify-content: center;
  transition: box-shadow .12s ease;
}
.ff-appbar-avatar:hover { box-shadow: 0 0 0 3px var(--soft); }

/* header dropdown menus (help, avatar) */
.ff-appmenu {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  min-width: 210px; padding: 5px; background: var(--bg);
  border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--sh-md);
}
.ff-appmenu-label { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); font-weight: 600; padding: 8px 10px 4px; }
.ff-appmenu-item {
  display: block; width: 100%; text-align: left; box-sizing: border-box;
  padding: 8px 10px; border: none; background: transparent; border-radius: 8px;
  font: inherit; font-size: 13.5px; color: var(--ink); text-decoration: none; cursor: pointer;
}
.ff-appmenu-item:hover { background: var(--soft); }
.ff-appmenu-sep { height: 1px; background: var(--line); margin: 5px 4px; }
.ff-appmenu-acct { min-width: 248px; }
.ff-appmenu-head { padding: 8px 10px 4px; }
.ff-appmenu-name { font-weight: 600; font-size: 13.5px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-appmenu-email { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; }

/* workspace sidebar: in-flow on desktop, collapsible, drawer on phones */
.ff-appside { max-height: 100%; flex: 0 0 248px; }
/* Collapsed = a 64px icon rail that expands to 248px on hover and PUSHES the page
   content (in-flow reflow), so it never overlaps or clips interactive content.
   Hamburger toggles the collapsed state (pin). */
@media (min-width: 901px) {
  .ff-appside.ff-appside-collapsed {
    flex: 0 0 64px; overflow: hidden; padding: 14px 8px;
    transition: flex-basis .2s ease, box-shadow .2s ease;
  }
  .ff-appside.ff-appside-collapsed:hover {
    flex: 0 0 248px; padding: 14px 12px;
    box-shadow: 6px 0 26px -6px rgba(10, 10, 12, 0.16);
  }
  /* Consistent icon rail: every nav item is a 40px-tall hit target with the icon
     centered on a shared box, even rhythm between items, and one hover/active
     affordance — the watchlist star sits on the same grid as the rest. */
  .ff-appside-collapsed .ff-rail-nav { gap: 4px; }
  .ff-appside-collapsed .ff-rail-nav .btn {
    justify-content: center !important; gap: 0; padding: 0 !important;
    min-height: 40px; height: 40px; border-radius: 10px;
  }
  .ff-appside-collapsed .ff-rail-nav .btn > svg { margin: 0 auto; }
  /* Icon centering must be REAL: labels/badges/locks fade via opacity below, but
     an opacity-0 flex item still holds its width, so justify-content centered an
     overflowing content box and every row's icon shifted left by half its hidden
     label+badge width (founder 7/8: "the logos aren't even lined up"). Collapse
     them to zero width in the strip; hover restores the natural layout. */
  .ff-appside-collapsed .ff-rail-nav .btn .grow,
  .ff-appside-collapsed .ff-rail-nav .btn .mono,
  .ff-appside-collapsed .ff-rail-nav .btn .ff-rail-lock {
    flex: 0 0 0px; width: 0; min-width: 0; overflow: hidden; margin: 0; padding: 0;
  }
  .ff-appside-collapsed:hover .ff-rail-nav .btn {
    justify-content: flex-start !important; gap: 10px; padding: 8px 10px !important; height: auto;
  }
  .ff-appside-collapsed:hover .ff-rail-nav .btn .grow { flex: 1 1 auto; width: auto; }
  .ff-appside-collapsed:hover .ff-rail-nav .btn .mono { flex: 0 0 auto; width: auto; }
  .ff-appside-collapsed:hover .ff-rail-nav .btn .ff-rail-lock { flex: 0 0 auto; width: 13px; }
  /* The outline star fills its 24-box edge-to-edge, so it reads optically larger
     than the line icons; scale it to match the shared box. */
  .ff-rail-star { transform: scale(0.88); }
  /* labels, badges, group headers, Recent card + foot fade out in the icon rail
     and back in on hover. Icons stay visible in the 64px strip. */
  .ff-appside-collapsed .ff-rail-nav .grow,
  .ff-appside-collapsed .ff-rail-nav .mono,
  .ff-appside-collapsed .ff-rail-group,
  .ff-appside-collapsed .ff-rail-now,
  .ff-appside-collapsed .ff-rail-foot { opacity: 0; transition: opacity .14s ease; white-space: nowrap; }
  .ff-appside-collapsed:hover .ff-rail-nav .grow,
  .ff-appside-collapsed:hover .ff-rail-nav .mono,
  .ff-appside-collapsed:hover .ff-rail-group,
  .ff-appside-collapsed:hover .ff-rail-now,
  .ff-appside-collapsed:hover .ff-rail-foot { opacity: 1; }
}
@media (max-width: 900px) {
  .ff-appside {
    position: fixed !important; top: 0; left: 0; height: 100vh !important;
    width: 272px !important; flex-basis: 272px !important; z-index: 60;
    transform: translateX(-100%); transition: transform .22s ease;
    box-shadow: 2px 0 22px rgba(10, 10, 12, 0.20);
  }
  .ff-appside.ff-appside-open { transform: translateX(0); }
  .ff-appside-overlay { position: fixed; inset: 0; background: rgba(10, 10, 12, 0.42); z-index: 55; }
}
@media (max-width: 640px) {
  .ff-appbar { grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; padding: 0 10px; }
}
@media (max-width: 460px) {
  .ff-appbar-brand .ff-wordmark { display: none; }
  /* The carrier report omits the rail toggle, so the wordmark (-> /account) is
     the ONLY way back to the workspace. Keep it visible there even on the
     narrowest phones, so a mobile report is never a dead end. */
  .ff-appbar-report .ff-appbar-brand .ff-wordmark { display: inline-flex; }
}

/* ⌘K command palette — the header pill (trigger) + the overlay it opens */
.ff-cmdk-trigger {
  display: flex; align-items: center; gap: 10px; width: 100%; max-width: 520px;
  background: var(--soft); border: 1px solid var(--line); border-radius: 10px;
  padding: 8px 10px 8px 12px; cursor: text; color: var(--faint);
  font-family: var(--sans); transition: border-color .12s ease, background .12s ease;
}
.ff-cmdk-trigger:hover { background: var(--bg); border-color: #d7d6cf; }
.ff-cmdk-trigger-ph { flex: 1; min-width: 0; text-align: left; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-cmdk-kbd, .ff-cmdk-esc {
  flex: 0 0 auto; font-family: var(--mono); font-size: 11px; font-weight: 600; color: var(--muted);
  background: var(--bg); border: 1px solid var(--line); border-radius: 5px; padding: 2px 6px; line-height: 1.4;
}
.ff-cmdk-esc { cursor: pointer; }
.ff-cmdk-scrim {
  position: fixed; inset: 0; z-index: 200; background: rgba(16, 18, 23, .34);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 12vh 16px 16px; -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.ff-cmdk {
  width: 100%; max-width: 600px; background: var(--bg); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: var(--sh-lg); overflow: hidden; animation: ff-cmdk-in .14s ease-out;
}
@keyframes ff-cmdk-in { from { opacity: 0; transform: translateY(-6px) scale(.99); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ff-cmdk { animation: none; } }
/* Anchored open: the palette DROPS from the header search pill (measured on open)
   instead of appearing as a centered modal. Positioned at the pill via inline
   top/left; transform-origin top so it scales + translates down from the bar. */
.ff-cmdk-scrim-anchored { display: block; padding: 0; }
.ff-cmdk-anchored {
  position: fixed; width: min(600px, 94vw); max-width: none;
  transform: translateX(-50%); transform-origin: top center;
  animation: ff-cmdk-drop .17s cubic-bezier(.16, 1, .3, 1);
}
@keyframes ff-cmdk-drop {
  from { opacity: 0; transform: translateX(-50%) translateY(-10px) scaleY(.96); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scaleY(1); }
}
@media (prefers-reduced-motion: reduce) { .ff-cmdk-anchored { animation: none; } }
/* At phone widths the anchored palette (positioned on the header pill's centre
   with translateX(-50%)) could overrun the viewport edge and clip. Clamp it to
   the viewport gutters and drop the horizontal transform so it never clips. */
@media (max-width: 560px) {
  .ff-cmdk-anchored {
    left: 8px !important; right: 8px; width: auto; max-width: none;
    transform: none; animation: ff-cmdk-in .14s ease-out;
  }
}
.ff-cmdk-input { display: flex; align-items: center; gap: 10px; padding: 13px 14px; border-bottom: 1px solid var(--line); }
.ff-cmdk-modebtn {
  display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
  font-family: var(--sans); font-size: 13px; font-weight: 600; color: #4a5361;
  background: var(--soft); border: 1px solid var(--line); border-radius: 8px; padding: 5px 8px; cursor: pointer;
}
.ff-cmdk-modebtn:hover { background: #efefe9; }
.ff-cmdk-modemenu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 5; min-width: 150px; padding: 5px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--sh-md);
}
.ff-cmdk-modeitem {
  display: flex; align-items: center; width: 100%; padding: 7px 9px; border: none; background: transparent;
  border-radius: 7px; font-family: var(--sans); font-size: 13px; color: var(--ink); cursor: pointer;
}
.ff-cmdk-modeitem:hover { background: var(--soft); }
.ff-cmdk-field {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-family: var(--sans); font-size: 15px; color: var(--ink); padding: 2px 0;
}
.ff-cmdk-body { max-height: 46vh; overflow-y: auto; padding: 6px; }
.ff-cmdk-sec { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); font-weight: 600; padding: 8px 10px 4px; }
.ff-cmdk-row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 9px 10px; border: none; background: transparent; border-radius: 9px; cursor: pointer; text-align: left; }
.ff-cmdk-row.on, .ff-cmdk-row:hover { background: var(--soft); }
.ff-cmdk-ic { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px; background: var(--soft); display: inline-flex; align-items: center; justify-content: center; font-family: var(--mono); font-weight: 700; font-size: 11px; color: var(--muted); }
.ff-cmdk-row.on .ff-cmdk-ic { background: var(--red-soft); color: #a30d26; }
.ff-cmdk-name { font-size: 14px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-cmdk-meta { font-family: var(--mono); font-size: 12px; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ff-cmdk-hint { padding: 16px 12px; font-size: 13px; color: var(--muted); }
/* tighter page padding for the account surface on phones */
@media (max-width: 640px) {
  .ff-account-pad { padding: 18px 14px 56px !important; }
}
/* tighter page padding for the account surface on phones */
@media (max-width: 640px) {
  .ff-account-pad { padding: 18px 14px 56px !important; }
}
/* top header (React Header + the static #ff-boot copy share .ff-topbar): on
   phones the About/Contact column overlaps the search pill — drop it (both
   destinations live in the footer) and give the search the freed width. */
@media (max-width: 640px) {
  .ff-topbar { grid-template-columns: auto minmax(0, 1fr) !important; gap: 10px !important; padding: 9px 14px !important; }
  .ff-topbar > nav { display: none !important; }
}

/* scrollbar */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #D6D5CE; border-radius: 8px; border: 3px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: #C2C1B9; }

/* Responsive 2-column block (Authority|Insurance, the two histories). Was inline
   `grid-template-columns:1fr 1fr`, which couldn't collapse on a phone — each
   column crushed to ~165px and the values clipped ("AUTHORIZED FOR HIRE", the
   grant year). As a class it stacks to one column <=640px; the divider column
   drops its left border + indent there so no stray rule floats over the stack. */
.ff-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 0 40px; }
.ff-2col-divider { border-left: 1px solid var(--line); padding-left: 40px; }
@media (max-width: 640px) {
  /* minmax(0,1fr), NOT 1fr: a bare 1fr floors at the widest child's min-content,
     so the history cards (wide timeline/ledger content) blew past the container
     to ~413px while the Registration card stayed 364px — they looked mismatched
     (founder 2026-06-23). minmax(0,…) lets the track shrink to the container so
     every card is the same width; inner content wraps/scrolls within. */
  .ff-2col { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .ff-2col > * { min-width: 0; }
  .ff-2col-divider { border-left: none; padding-left: 0; padding-top: 4px; border-top: 1px solid var(--line); }
}

/* ============================================================
   MOBILE RETHINK (<=640px) — 2026-06-22
   The carrier report is a desktop dossier; on a phone the dense, multi-column
   clusters cram and clip (the 4-up BASIC snapshot was the worst). This layer
   does ONE job: stack every dense cluster into clean, full-width, non-clipping
   blocks. Progressive disclosure (primary number visible, detail behind a tap)
   lives in the JSX, not here — hiding info in CSS would delete it, not condense
   it. Keep this block append-only and self-contained so it's easy to review.
   ============================================================ */
@media (max-width: 640px) {
  /* tighter page gutters so cards get the full phone width */
  .ff-ovgrid { gap: 14px; }

  /* 4-up stat snapshot (Safety + Overview "what the data says") — the headline
     break. flex 1 1 132px crushed 4 cells into ~80px each and clipped the
     labels. Go 2x2: each cell gets ~150px, nothing clips. The flex left-border
     dividers become grid gaps. */
  .ff-sumstats {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 18px 10px;
    width: 100%;
  }
  .ff-sumstats > div { flex: none !important; padding: 0 4px !important; }
  .ff-sumstats > div + div { border-left: none !important; }
  /* keep a hairline only between the two columns, not under rows */
  .ff-sumstats > div:nth-child(2n) { border-left: 1px solid var(--line) !important; }

  /* crash exposure counts (total / injury / fatal): full width, three even
     cells centered across it (each cell's content is already center-aligned),
     so the trio reads as a balanced row instead of left-packed. */
  .ff-crash-counts { width: 100%; justify-content: space-around !important; flex: 1 1 100% !important; }
  .ff-crash-cell { flex: 1 1 0 !important; min-width: 0 !important; }
  /* crash windows already wrap at min-width:200px; drop that floor so two
     windows stack cleanly instead of leaving a lonely wide one */
  .ff-crash-win { min-width: 0 !important; flex: 1 1 100% !important; }
  .ff-crash-peer { min-width: 0 !important; flex: 1 1 100% !important; }
  /* the prior->last 12mo comparison stacks vertically on a phone, so the trend
     arrow should point DOWN, not right; the delta+arrow sit centered between
     the two cards. */
  .ff-crash-mid { flex-direction: row !important; gap: 12px !important; padding: 2px 0 !important; }
  .ff-crash-arrow { display: inline-block; transform: rotate(90deg); }

  /* the safety split (table | peer panel) already stacks at 1080px; make sure
     the inner pair does too so nothing sits half-width on a phone */
  .ff-safety-pair > section { flex: 1 1 100% !important; }

  /* verdict flag chips on a phone: long flag text ("2 BASICs at the FMCSA
     intervention threshold") wraps to two lines — a rounded rectangle holds
     that better than the desktop pill (founder 2026-06-23 precedent). */
  .ff-flag-chip { border-radius: 12px; }
  .ff-flagchip-txt { flex: 1 1 auto; min-width: 0; line-height: 1.35; }

  /* address map: trim from 300px so it isn't a dominant block on a phone */
  .ff-addr-map > div, .ff-addr-map iframe { min-height: 220px !important; }

  /* doccap: "Carrier report" + refresh on row 1, the data-pull date on row 2.
     The desktop one-liner squeezed three baselines into a cramped row on a
     phone (founder 2026-06-22). */
  .ff-doccap-m { flex-direction: column; align-items: stretch; gap: 5px; }

  /* tab strip: show each tab's short alias AND drop the per-tab icon so all five
     fit one row (full names + icons overflowed and the extra tabs were
     unreachable on a narrow, non-touch window where you can't swipe-scroll).
     :has — Safari 17 / Chrome 105+, fine on the phones this targets. */
  .ff-tab-short { display: inline; }
  .ftab:has(.ff-tab-short) .ff-tab-full { display: none; }
  .ftab svg { display: none !important; }
  /* min-height 40 = iOS-grade tap target (P2-4); the sliding pill reads
     active.offsetHeight so it grows to match. */
  .ftab { padding: 7px 9px; gap: 0; flex: 0 0 auto; justify-content: center; font-size: 13px; min-height: 40px; }
  /* The five short labels fit ~390 but sit flush to the edge, and overflow the
     strip below ~370. Make the TRACK its own horizontal scroller (never the
     page) with a right spacer so the last tab can't edge-clip at any width, plus
     a faint edge fade so the extra tabs read as swipeable. overflow-y:hidden
     (not visible — auto would show a stray scrollbar); the notification dot sits
     ~14px inside the taller track, so it is not clipped. */
  .ftabs {
    padding: 6px 4px; justify-content: flex-start;
    overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
    background-color: #f1efe9;
    background-image:
      linear-gradient(90deg, #f1efe9 30%, rgba(241,239,233,0)),
      linear-gradient(90deg, rgba(241,239,233,0), #f1efe9 70%),
      radial-gradient(farthest-side at 0 50%, rgba(11,12,14,.16), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(11,12,14,.16), transparent);
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 22px 100%, 22px 100%, 12px 100%, 12px 100%;
    background-attachment: local, local, scroll, scroll;
  }
  .ftabs::-webkit-scrollbar { display: none; }
  /* scroll-end breathing room: padding-right on a flex scroll container is
     dropped by WebKit at the end of scroll, so pin it to the last tab. */
  .ftab:last-child { margin-right: 14px; }
  .ff-tabdot { top: -3px; right: -10px; }

  /* section headers: title + sub take the full width; the action(s) on the
     right (Consistent / View fleet, etc.) drop below instead of squeezing the
     title into a tall narrow column. The decorative rule is dropped. */
  .ff-sechead { flex-wrap: wrap; row-gap: 11px; }
  .ff-sechead-title { flex: 1 1 100% !important; }
  .ff-sechead .ff-shead-rule { display: none !important; }
  .ff-sechead > *:last-child { flex: 1 1 100%; justify-content: flex-start; }

  /* section heads / body copy: a touch smaller so dense tabs read as one column
     without horizontal strain. Values stay prominent. */
  .ff-vitals .ff-vital-v { font-size: 18px; }

  /* FMCSA BASIC table — a 4-6 column grid whose column minimums (cat 210 + pct
     230 + viol 62 + status 110 + gaps) total ~660px, far past a phone. That
     forced a whole-page horizontal scroll and zoomed the page out on some
     carriers (data-dependent: wider captions push it over). Reflow each row to
     a single stacked column so it fits 390px with nothing cut off: category,
     then the percentile bar + read, then violations (labeled, since the column
     header is dropped), then the status pill. */
  .ff-basic-head { display: none !important; }
  .ff-basic-row {
    grid-template-columns: 1fr !important;
    gap: 7px !important;
    padding: 15px 18px !important;
  }
  /* left-align the cells that were right-aligned for the desktop columns */
  .ff-basic-row > * { text-align: left !important; justify-content: flex-start !important; }
  .ff-basic-row .ff-basic-viol::before {
    content: "Violations: "; color: var(--muted); font-family: var(--sans);
  }
  /* a hair of separation so each BASIC reads as its own block */
  .ff-basic-row { border-bottom: 1px solid var(--line) !important; }

  /* generated key/value lists (Operating authority, Insurance, Registration)
     use .cr-dl with a fixed 180px label column — on a phone that left only
     ~150px for the value and clipped dates/operation strings ("Jan 9, 197|7").
     Stack label-over-value so every value gets the full column width. The
     dt margin restores group separation a single-column grid gap can't. */
  .cr-dl { grid-template-columns: 1fr !important; gap: 3px 0 !important; }
  .cr-dl dt { margin-top: 12px; }
  .cr-dl dt:first-of-type { margin-top: 0; }
}

/* very narrow (<=380px, iPhone mini / SE landscape-of-portrait): the 2x2 stat
   grid can still feel tight — drop to a single column so labels never wrap mid
   word. Crash cells too. */
@media (max-width: 380px) {
  .ff-sumstats { grid-template-columns: 1fr; gap: 14px; }
  .ff-sumstats > div:nth-child(2n) { border-left: none !important; }
  .ff-crash-cell { flex: 1 1 100% !important; }
}

/* ── Expandable flag rows (verdict banner) ─────────────────────────────────── */
.ff-flags { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* Compact content-width chips + ONE shared panel per group (redesign, founder
   2026-07-15). A chip is sized to its label — no 2-up stretching, no dead
   space — and NEVER moves or resizes; clicking selects it and the group's
   shared .ff-flag-panel (rendered under the chip rows) shows the detail. The
   old per-chip width/height expansion and the hover tooltip are gone: the
   panel is the single disclosure mechanism. */
.ff-flag-chip { display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  border: 1px solid var(--line); border-radius: 999px; background: #fff; cursor: pointer;
  padding: 7px 13px; font: inherit; text-align: left; transition: border-color .15s, background .15s; }
.ff-flag-chip:hover { border-color: #d8d4cc; background: rgba(0,0,0,.015); }
.ff-flag-sev { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ff-flag-title { min-width: 0; font-weight: 700; font-size: 14px; line-height: 1.25; color: var(--ink); }
.ff-flag-chev { flex: 0 0 auto; display: inline-flex; transition: transform .25s cubic-bezier(.32,.72,0,1); }
.ff-flag-chip.open .ff-flag-chev { transform: rotate(90deg); }
/* Selected state, severity-tinted (data-ff-flag = the stable severity hook). */
.ff-flag-chip.open[data-ff-flag="critical"] { border-color: var(--red); background: var(--danger-sf); }
.ff-flag-chip.open[data-ff-flag="caution"] { border-color: var(--amber); background: var(--amber-sf); }
.ff-flag-chip.open:not([data-ff-flag="critical"]):not([data-ff-flag="caution"]) { border-color: var(--muted); background: var(--soft); }
/* The group's shared detail panel, directly beneath its chip rows. */
.ff-flag-panel { border: 1px solid var(--line); border-radius: 11px; background: #fff;
  padding: 12px 14px 14px; box-shadow: 0 4px 16px rgba(0,0,0,.06); }
@media (prefers-reduced-motion: no-preference) {
  .ff-flag-panel { animation: ff-flag-panel-in .18s ease-out; }
  @keyframes ff-flag-panel-in { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
}
.ff-flag-explain { font-size: 12.5px; color: var(--text, #374151); line-height: 1.5; margin: 0 0 8px; font-weight: 400; }
.ff-chain { list-style: none; margin: 6px 0 0; padding: 0; }
.ff-chain li { display: flex; align-items: center; gap: 9px; padding: 6px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.ff-chain li:last-child { border-bottom: 0; }
.ff-chain-t { flex: 1 1 auto; min-width: 0; }
.ff-chain-n { font-weight: 600; }
.ff-chain-d { color: var(--muted); font-family: var(--mono, ui-monospace, monospace); font-size: 11.5px; }
.ff-tag { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: 2px 6px;
  border-radius: 5px; background: var(--red-sf, #fdecee); color: var(--red); flex: 0 0 auto; white-space: nowrap; }
.ff-tag.units { background: rgba(0,0,0,.05); color: var(--ink); }
.ff-dtable { width: 100%; border-collapse: collapse; font-size: 12.5px; margin-top: 6px; }
.ff-dtable th, .ff-dtable td { text-align: left; padding: 5px 7px; border-bottom: 1px solid var(--line); }
.ff-dtable th { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 600; }
.ff-dtable td.num, .ff-dtable th.num { text-align: right; font-family: var(--mono, ui-monospace, monospace); }
.ff-statrow { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 8px; }
.ff-stat .n { font-family: var(--mono, ui-monospace, monospace); font-size: 18px; font-weight: 700; color: var(--ink); }
.ff-stat.crit .n { color: var(--red); }
.ff-stat .l { font-size: 11px; color: var(--muted); margin-top: 2px; line-height: 1.35; }
.ff-flag-note { font-size: 12px; color: var(--muted); margin-top: 10px; line-height: 1.5; }
.ff-flag-deeplink { display: inline-flex; align-items: center; gap: 6px; margin-top: 11px; font-size: 12.5px;
  font-weight: 600; color: var(--red); background: transparent; border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 11px; cursor: pointer; }
.ff-flag-deeplink:hover { background: var(--red-sf, #fdecee); border-color: var(--red); }

/* ── Sourcing overhaul (2026-07-01): lane bar, chip rail, body grid ────────── */
.ff-src-nl { display: flex; align-items: center; gap: 8px; flex: 1 1 260px; min-width: 220px; }
.ff-src-nl-input { flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font: inherit; font-size: 13.5px; color: var(--ink); }
.ff-src-nl-input::placeholder { color: var(--faint); }
/* NL-first composer (2026-07-05): the describe box is the primary full-width row
   (bigger type, filled/focus-lit field), the structured lane is the secondary
   refine row beneath — "just describe it" reads as the default path. */
.ff-src-composer { display: flex; flex-direction: column; gap: 10px; padding: 12px 14px; }
.ff-src-nl-primary { flex: 1 1 auto; gap: 10px; padding: 12px 14px;
  background: var(--soft); border: 1px solid var(--line); border-radius: 12px; transition: border-color .12s, background .12s; }
.ff-src-nl-primary:focus-within { border-color: var(--red); background: var(--bg); }
.ff-src-nl-primary .ff-src-nl-input { font-size: 16px; }
.ff-src-nl-primary .ff-src-nl-input::placeholder { color: var(--muted); }
.ff-src-refine { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ff-src-refine-lbl { flex: 0 0 auto; font-size: 12.5px; font-weight: 500; color: var(--faint); }
.ff-src-refine .ff-city-field { flex: 0 1 220px; min-width: 170px; }

.ff-chip-rail { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.ff-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line);
  background: var(--bg); border-radius: 999px; padding: 4px 11px; font-size: 12.5px; font-weight: 600;
  color: var(--muted); cursor: pointer; line-height: 1.25; font-family: inherit; }
.ff-chip:hover { border-color: var(--ink); color: var(--ink); }
.ff-chip.on { color: var(--ink); border-color: var(--ink); background: var(--soft); }
.ff-chip.tog { font-weight: 500; }
.ff-chip.tog.on { font-weight: 600; }
.ff-chip.add { border-style: dashed; }
.ff-chip.clear { border: none; background: transparent; text-decoration: underline; font-weight: 500; }
.ff-chip-x { color: var(--faint); font-weight: 400; margin-left: 1px; }
.ff-chip:hover .ff-chip-x { color: var(--red); }
/* native select skinned to the same pill geometry (one control grammar) */
.ff-chip-sel { border-radius: 999px !important; padding: 4px 26px 4px 11px !important;
  font-size: 12.5px !important; font-weight: 600; width: auto !important; }

/* FILTER BAR — always-visible labeled controls (the NL parse writes into
   these; a control it just set flashes via .ff-nl-flash). */
.ff-src-controls { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.ff-src-controls .ff-ctl { border-radius: 10px; }
.ff-src-controls .ff-ctl .ff-select { min-width: 132px; }
.ff-src-controls .ff-ctl .ff-pickbtn { min-width: 150px; max-width: 200px; }
.ff-ctl-fleet .ff-input.sm { width: 64px; }
.ff-ctl-togs { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; padding-bottom: 4px; }
@keyframes ff-nl-flash {
  0%   { box-shadow: 0 0 0 3px rgba(200, 16, 46, .30); background: #fff2f4; }
  100% { box-shadow: 0 0 0 3px rgba(200, 16, 46, 0); background: transparent; }
}
.ff-nl-flash { animation: ff-nl-flash 1.6s ease-out both; }

/* skeleton result rows while the first search runs */
@keyframes ff-skel-sheen { 0% { background-position: -160px 0; } 100% { background-position: 240px 0; } }
.ff-skel-row { padding: 14px 16px; display: flex; flex-direction: column; gap: 9px; }
.ff-skel { height: 12px; border-radius: 6px; background: var(--soft)
  linear-gradient(90deg, transparent, rgba(255,255,255,.75), transparent) no-repeat -160px 0 / 160px 100%;
  animation: ff-skel-sheen 1.3s linear infinite; }
.ff-skel-title { width: 42%; height: 14px; }
.ff-skel-line { width: 78%; }
.ff-skel-line.short { width: 55%; }
@media (prefers-reduced-motion: reduce) { .ff-skel { animation: none; } .ff-nl-flash { animation: none; } }

/* results ease in with a light stagger once a search lands.
   Opacity-only, deliberately: animating transform with fill `both` left a
   computed identity transform on every row, making each row a stacking
   context that trapped the note popover's z-index under later siblings
   (Save unreachable). Fade only = no lingering transform, no trap. */
@keyframes ff-row-in { from { opacity: 0; } to { opacity: 1; } }
.ff-src-list > .ff-src-row { animation: ff-row-in .26s ease both; }
.ff-src-list > .ff-src-row:nth-child(2) { animation-delay: .03s; }
.ff-src-list > .ff-src-row:nth-child(3) { animation-delay: .06s; }
.ff-src-list > .ff-src-row:nth-child(4) { animation-delay: .09s; }
.ff-src-list > .ff-src-row:nth-child(5) { animation-delay: .12s; }
@media (prefers-reduced-motion: reduce) { .ff-src-list > .ff-src-row { animation: none; } }

/* MAP BAND — the lane map is its own full-width section above the results
   (no side panel: the carrier rows keep the whole width). The svg is
   height-capped and centered; zooming to a lane fills the band. */
.ff-map-band { padding: 8px 12px 4px; }
.ff-lane-map-wrap { position: relative; width: 100%; }
.ff-map-band .ff-lane-map { display: block; width: 100%; height: clamp(240px, 32vw, 380px); }
/* Fast dot tooltip: legal name + USDOT/state/fleet, positioned wrap-relative and
   flipped away from the map edges so it never clips. Pointer-events off so it never
   eats the hover it describes. */
.ff-dot-tip {
  position: absolute; z-index: 6; pointer-events: none;
  background: var(--ink); color: #fff; border-radius: 9px; padding: 7px 10px;
  box-shadow: var(--sh-md); max-width: 230px;
}
.ff-dot-tip-name { font-size: 12.5px; font-weight: 600; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 210px; }
.ff-dot-tip-meta { font-size: 11px; opacity: 0.8; margin-top: 2px; letter-spacing: -0.01em; white-space: nowrap; }
.ff-map-foot-band { display: flex; flex-direction: row; align-items: center; gap: 12px;
  flex-wrap: wrap; padding: 4px 4px 6px; border-top: 1px solid var(--line); margin-top: 6px; }
.ff-map-foot-band .ff-lane-summary { justify-content: flex-start; flex: 0 0 auto; }
/* the 46% place cap is for the narrow composer; inside the shrink-wrapped foot band it
   clips the "Destination" placeholder mid-word — let the labels size naturally here */
.ff-map-foot-band .ff-lane-place { max-width: none; }
.ff-map-dots-note { margin-left: auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

/* dossier-grade numerics + the blocking-only hairline rail */
.ff-src-row { font-variant-numeric: tabular-nums; }
.ff-src-row.ff-src-blocked { box-shadow: inset 3px 0 0 var(--red); }
/* map-dot hover ↔ row highlight (both directions share this class) */
.ff-src-row.hl { border-color: #c8102e; box-shadow: 0 0 0 2px rgba(200, 16, 46, .14); }

/* ── One empty-state component (audit C2) ─────────────────────────────────── */
.ff-empty { padding: 40px 24px; text-align: center; display: flex; flex-direction: column; align-items: center; }
.ff-empty-icon {
  width: 44px; height: 44px; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--soft); color: var(--muted); border: 1px solid var(--line);
}
.ff-empty-h { font-weight: 650; font-size: 15px; margin-top: 14px; }
.ff-empty-b { margin-top: 6px; max-width: 420px; line-height: 1.5; }
.ff-empty-cta { margin-top: 16px; }

/* ── Workspace polish: one PageHeader + SectionCard + toolbar + table system ──
   Every signed-in workspace page (Alerts, Lists, Do-not-use, Import, Proof,
   Your reports, Policy, Graph explorer, Bulk vetting, Carrier sourcing) reads
   from these classes so the surface stops looking hand-assembled. Density scale:
   app text 13.5–14px, controls ~34px, 8px grid, ~1180 content width. */

/* content column — one width + gutter for the whole workspace */
.ff-ws-pad { max-width: 1180px; margin: 0 auto; padding: 26px 28px 72px; width: 100%; }
@media (max-width: 640px) { .ff-ws-pad { padding: 18px 14px 56px; } }
/* a reading-width cap for form-shaped pages (Import, Policy) inside the wide page */
.ff-ws-form { max-width: 720px; }

/* PageHeader */
.ff-pagehead { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 22px; }
.ff-pagehead-main { min-width: 0; }
.ff-pagehead-title { font-size: 24px; font-weight: 650; letter-spacing: -0.02em; line-height: 1.16; margin: 0; color: var(--ink); }
.ff-pagehead-desc { font-size: 13.5px; line-height: 1.5; color: var(--muted); margin: 6px 0 0; max-width: 660px; }
.ff-pagehead-stats { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 0; margin-top: 12px; }
.ff-pagehead-stat { font-size: 12.5px; color: var(--muted); }
.ff-pagehead-stat b { font-family: var(--mono); font-weight: 600; font-size: 12.5px; color: var(--ink); letter-spacing: -0.02em; }
.ff-pagehead-stat + .ff-pagehead-stat::before { content: "·"; color: var(--faint); margin: 0 8px; }
.ff-pagehead-right { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; padding-top: 2px; }
@media (max-width: 620px) {
  .ff-pagehead { flex-direction: column; gap: 14px; }
  .ff-pagehead-right { width: 100%; flex-wrap: wrap; }
}

/* SectionCard */
.ff-sectioncard { padding: 0; overflow: hidden; }
.ff-sectioncard-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 18px; border-bottom: 1px solid var(--line); background: var(--soft);
}
.ff-sectioncard-kicker {
  font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--muted);
}
.ff-sectioncard-action { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.ff-sectioncard-body { padding: 18px; }
.ff-sectioncard-body-flush { padding: 0; }

/* Toolbar row — the strip of filters/actions directly under a header or card */
.ff-ws-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 10px 14px; flex-wrap: wrap; }
.ff-ws-toolbar-l, .ff-ws-toolbar-r { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }

/* Table system — 40–44px rows, mono uppercase 11px column kickers, hover tint */
.ff-tbl { width: 100%; }
.ff-tbl-head {
  display: grid; align-items: center; gap: 10px; padding: 9px 16px;
  border-bottom: 1px solid var(--line); background: var(--soft);
}
.ff-tbl-kicker {
  font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--muted); background: none; border: none; padding: 0;
  text-align: left;
}
button.ff-tbl-kicker { cursor: pointer; }
.ff-tbl-kicker.num { text-align: right; justify-self: end; }
.ff-tbl-row {
  display: grid; align-items: center; gap: 10px; padding: 10px 16px;
  border-bottom: 1px solid var(--line); transition: background .1s;
}
.ff-tbl-row:last-child { border-bottom: none; }
.ff-tbl-row:hover { background: var(--soft); }
.ff-tbl-num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; justify-self: end; letter-spacing: -0.01em; }
/* Row-action controls (Quick look, Remove, add/edit note) are mouse-precise but
   finger-small on a phone (~19-25px). On touch or a narrow viewport give each a
   >=40px hit zone, centered — the icon/label keep their size, they just sit in a
   bigger tap target (same idiom as the narrow-screen header nav / .ff-copy). */
@media (hover: none), (max-width: 640px) {
  .ff-rowact {
    min-width: 40px; min-height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
  }
}

/* clickable summary card (named lists, and the like) */
.ff-listcard { transition: border-color .12s, box-shadow .12s; }
.ff-listcard:hover { border-color: #d6dae1; box-shadow: 0 2px 8px rgba(16, 24, 40, .07); }

/* ============================================================
   MOBILE CARRIER-REPORT FIXES (round 0716) — all scoped ≤640px / touch, so
   the desktop report is byte-identical. Each rule maps to one review finding.
   ============================================================ */

/* P1-2 — insurance-history table (dense carriers) pushed the whole report main
   ~35px sideways because its container was overflow-x:visible. Contain it in its
   own horizontal scroller INSIDE the card (same idiom as .eq-table-scroll); the
   card's 22px padding stays as the right gutter. Desktop: the 5-column table
   fits, so overflow-x:auto is inert and nothing moves. */
.cr-ins-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 640px) {
  .cr-ins-scroll {
    scrollbar-width: thin;
    background-color: var(--bg);
    background-image:
      linear-gradient(90deg, var(--bg) 30%, rgba(255,255,255,0)),
      linear-gradient(90deg, rgba(255,255,255,0), var(--bg) 70%),
      radial-gradient(farthest-side at 0 50%, rgba(11,12,14,.16), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(11,12,14,.16), transparent);
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 24px 100%, 24px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}

/* P2-3 — hero action cluster (Export PDF / Share / Watch) was right-aligned with
   a ~55% dead left gutter and Watch wrapped to its own right-aligned row. Inline
   styles set flex/justify, so override with !important: full-width, left-aligned
   wrap on a phone. */
@media (max-width: 640px) {
  .ff-hero-actions { flex: 1 1 100% !important; justify-content: flex-start !important; }
}

/* P2-4 — raise sub-40px hit areas to the iOS ~44 floor on touch/narrow only
   (padding/min-size, never font-size). .ftab is handled in the tab block above. */
@media (hover: none), (max-width: 640px) {
  .btn.sm { min-height: 40px; }          /* Export PDF, Watch, Show evidence */
  .ff-copylink { width: 40px; height: 40px; }   /* Copy link */
  .ff-contact > a { min-height: 40px; }  /* contact tel:/mailto: rows */
  .ff-ask-input { min-height: 40px; }    /* grounded-Ask text field */
}

/* P2-5 — a filter/summary chip (fleet-cluster or corridor line) overflowed the
   viewport ~20px on dense carriers and scrolled main. Chips are white-space:
   nowrap; let a long one wrap and cap at the container. Also stack the corridor
   evidence row (a no-wrap space-between whose right stats group pushed past the
   edge). */
@media (max-width: 640px) {
  .chip { max-width: 100%; white-space: normal; }
  .ff-corridor-row { flex-wrap: wrap; row-gap: 6px; }
  .ff-corridor-row > * { min-width: 0; }
}

/* P2-6 — the observed-equipment table already scrolls inside .eq-table-scroll,
   but the ≤760 edge fade was too faint and the last MAKE column read as cut off.
   Stronger, wider fade at ≤640 (re-declared as longhands so it wins on source
   order over the ≤760 shorthand). */
@media (max-width: 640px) {
  .eq-table-scroll {
    background-color: var(--bg);
    background-image:
      linear-gradient(90deg, var(--bg) 34%, rgba(255,255,255,0)),
      linear-gradient(90deg, rgba(255,255,255,0), var(--bg) 66%),
      radial-gradient(farthest-side at 0 50%, rgba(11,12,14,.24), transparent),
      radial-gradient(farthest-side at 100% 50%, rgba(11,12,14,.24), transparent);
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 30px 100%, 30px 100%, 20px 100%, 20px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}

/* P2-7 — provenance/freshness line: on the reconstructed (FMCSA-outage) path the
   long label + " · see status" competed as flex items and wrapped raggedly. Let
   it flow as one left-aligned text block; keep "see status" from breaking across
   its two words. (This span only renders in the ≤640 doccap branch.) */
@media (max-width: 640px) {
  .ff-doccap-fresh { display: block; line-height: 1.5; }
  .ff-doccap-fresh svg { vertical-align: -2px; margin-right: 5px; }
  .ff-doccap-fresh a { white-space: nowrap; }
}
