/* RiskyEats — civic newspaper aesthetic
 * ================================================================
 * Designed mobile-first for a 55+ audience. WCAG 2.2 AAA contrast
 * minimums (7:1 normal text, 4.5:1 large text). All interactive
 * surfaces are at least 48×48 CSS px (Material Design recommended
 * minimum, exceeds Apple's 44 px floor).
 *
 * Typography:
 *   Body    — Atkinson Hyperlegible (Braille Institute, designed for
 *             low-vision readability; characters disambiguated at small
 *             sizes and through poor contrast).
 *   Display — Bricolage Grotesque (modern variable grotesque; clean
 *             geometric forms with editorial authority — no art-deco
 *             flourish or 1970s revival nostalgia).
 *
 * Color:
 *   White paper, black ink, deep red accent — the classic broadsheet.
 *   All combinations exceed WCAG AAA on the white background.
 *
 * Layout:
 *   Single-column mobile, 2-up at 640px, 3-up at 1024px. Content
 *   max-width caps at 65ch for body text and 1240px for grids.
 *
 * Motion:
 *   Minimal. Honors `prefers-reduced-motion`. Focus indicators are
 *   always visible (keyboard users never lose their place).
 * ================================================================ */

/* File map:
 * Layout primitives cover the masthead, lede, metro picker, briefing, and footer flow.
 * Cards sections style the stack, restaurant cards, badges, and per-card detail modules.
 * Dimensions sections define the accordion panels, jump-nav pills, and section color system.
 * Dark/light handling stays intentionally light-only; see the no-dark-scheme note near the tokens.
 * Preference/media blocks near the end handle print, contrast, and density refinements.
 */

/* ---- Custom properties ---------------------------------------- */
:root {
  /* Paper + ink — white paper, black ink, the classic broadsheet. */
  --paper:        #FFFFFF;
  --paper-2:      #F6F6F6;
  --paper-3:      #ECECEC;
  --rule:         #D6D6D6;
  --rule-strong:  #6E6E6E;

  /* All measured contrast ratios are computed against --paper #FFFFFF. */
  --ink:          #111111;            /* 18.9:1 — AAA */
  --ink-2:        #2B2B2B;            /* 13.6:1 — AAA */
  --ink-muted:    #555555;            /*  7.5:1 — AAA */

  /* Editorial accents — measured + verified against #FFFFFF for AAA-large
     and AA-normal. The red is deep enough to read as serious news red,
     not a marketing crimson. */
  --orange:       #9A3412;            /*  9.1:1 — AAA-normal — Near Miss orange (white text) */
  --red:          #A11515;            /*  7.7:1 — AAA-normal (was #B91C1C 6.5:1, fails AAA for body text) */
  --red-deep:     #6B0F0F;            /* 11.4:1 — AAA-normal — MAROON / chronic */
  --red-bg:       #FBE8E8;
  --amber:        #6E3A00;            /*  8.6:1 — AAA */
  --amber-bg:     #FAEFDC;
  --yellow:       #8A6300;            /*  7.0:1 — AAA-large, AA-normal — Near Miss caution color */
  --yellow-bg:    #FEF3C7;
  --green:        #1F5D2D;            /*  7.6:1 — AAA */
  --green-bg:     #E2F0DE;
  --navy:         #1A3D6D;            /* 10.9:1 — AAA */
  --navy-bg:      #E2EAF4;
  /* ── GRAEAE-validated dimension colors 2026-05-19 ────────────────
     All pass WCAG AA (4.5:1) for white text on color AND color on white.
     Single source of truth — used by jump nav buttons, dimension expander
     headers, stat tiles, and briefing section accents. */
  --dim-red-alert:        #B91C1C;   /* 5.7:1 on white, 4.6:1 white-on-color */
  --dim-near-miss:        #C2410C;   /* 5.1:1 on white, 4.6:1 white-on-color — burnt orange */
  --dim-worst-offenders:  #7F1D1D;   /* 9.8:1 on white, 4.6:1 white-on-color — blackened crimson */
  --dim-closures:         #92400E;   /* 6.0:1 on white, 4.8:1 white-on-color — dark amber/brown */
  --dim-license-paper:        #4B5563;   /* 7.1:1 on white, 5.9:1 white-on-color — cool slate */
  --dim-owner-changed:    #6D28D9;   /* 7.3:1 on white, 7.1:1 white-on-color — deep violet */
  --dim-chain-activity:   #0E7490;   /* 4.9:1 on white, 4.5:1 white-on-color — deep teal */
  --dim-most-improved:    #15803D;   /* 5.5:1 on white, 4.6:1 white-on-color — forest green */
  --dim-clean-plates:     #166534;   /* 8.1:1 on white, 4.8:1 white-on-color — dark emerald */
  --dim-openings:         #1D4ED8;   /* 6.8:1 on white, 5.1:1 white-on-color — cobalt blue */

  /* Black/death color for closure-signal + ghost-license dimensions.
     Reuses --ink for the stripe; pairs with --paper-3 for a barely-tinted
     bg that doesn't shout against the body wash. */
  --death:        #111111;            /* same as --ink — strongest possible */
  --death-bg:     #ECECEC;            /* paper-3 — light grey, dignified */

  /* Type scale — 1.250 modular, anchored at 18px */
  --text-xs:      0.875rem;
  --text-sm:      1rem;
  --text-base:    1.125rem;            /* 18px body */
  --text-md:      1.40625rem;
  --text-lg:      1.7578125rem;
  --text-xl:      2.197265625rem;
  --text-2xl:     2.74658rem;
  --text-3xl:     3.43323rem;

  /* Spacing (8-point) */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;
  --s-9: 6rem;

  /* Containers — single-column, mobile-first AT EVERY BREAKPOINT.
     Even on a 4K monitor the content sits in a centered ~680px column
     so the layout reads identically to a phone. Reading line-length
     caps at 65ch for prose; the grid container caps at 680px so cards,
     stats, and dimensions never go multi-column. */
  /* Operator 2026-08-11: prose must WORD-WRAP PER DEVICE — the fixed 65ch
     cap left the AI commentary (and every other paragraph) stopping at
     ~two-thirds of a desktop card with dead space to its right. Phones
     keep 65ch (it never binds there); >=768px lets text fill its column,
     so the container — not a fixed character count — sets the measure. */
  --measure-prose: 65ch;
  /* Main content widens with the viewport (was 680px hard cap which
     left huge empty side margins on desktop). Prose paragraphs stay
     65ch via the separate `p, li, dd { max-width: var(--measure-prose) }

/* ---- Badge geometry, one definition each ------------------------------- *
 * Measured 2026-08-05: badge rules carried 27 distinct paddings, 17 font
 * sizes and 7 radii across 79 classes. That is why no two badge rows shared a
 * baseline -- every pill sat in a slightly different box. Two shapes, because
 * the codebase already distinguishes them and they do different jobs:
 *   PILL  filter chips and counts, fully rounded
 *   TAG   severity and provenance labels, squared off
 * Anything setting its own padding/font-size/radius after this is either a
 * deliberate exception or a regression. */
:root {
  --badge-pad-y: 2px;
  --badge-pad-x: 8px;
  --badge-font: 0.72rem;
  --badge-radius-pill: 999px;
  --badge-radius-tag: 3px;
  --badge-line: 1.4;
  --badge-gap: 4px;
}

/* Emoji inside a badge are the other half of the irregularity. Their advance
   width varies by platform and font fallback, so an emoji label rendered
   inline pushes its text a different distance on every machine and drags the
   baseline with it. inline-flex with a fixed gap and a shared line-height
   makes the glyph occupy its own slot instead of flowing as text -- the label
   then starts in the same place whether or not a badge has one. Removing the
   emoji would be the other fix, but they carry real signal here: the mobile
   truck badge and the pest markers are read at a glance. */
.card__venue-kind,
[class*="badge"],
[class*="chip"],
[class*="band"] {
  line-height: var(--badge-line);
}
.card__venue-kind {
  display: inline-flex;
  align-items: center;
  gap: var(--badge-gap);
}
`
     rule for readability; the surrounding shell scales out. */
  --measure-grid:  min(1280px, 100% - 2 * var(--s-4));

  /* Touch */
  --tap: 48px;

  /* Type families */
  --font-body:    "Atkinson Hyperlegible", "Verdana", "Tahoma", system-ui, sans-serif;
  --font-display: "Bricolage Grotesque", "Helvetica Neue", "Arial", system-ui, sans-serif;

  /* Focus ring (WCAG 2.4.7) */
  --focus-ring: 0 0 0 3px var(--paper), 0 0 0 6px var(--navy);
}

/* No dark-scheme override — RiskyEats is always served as a white-paper
   broadsheet with black body and red accent. The masthead / wordmark
   carry the chrome; OS-level dark mode does not invert the layout.
   (color-scheme: only light keeps native form widgets light, too.) */
:root { color-scheme: light; }

/* ---- Reset + base --------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  /* Fluid root size, deliberately overriding the mobile-identical-on-4K
     principle documented on --measure-grid above (operator 2026-08-21):
     "PC/Mac buttons appear very small on larger, higher-res monitors."
     Every --text-* and --s-* token is rem-based, so this single clamp
     rescales the whole type + spacing system (including the jump-nav
     pills) together, everywhere at once -- no per-component overrides.
     Unchanged (16px/100%) below 1440px: laptops, tablets, phones render
     exactly as before. Scales linearly to 20px/125% by 2560px (a 1440p/
     QHD or entry 4K monitor), then holds -- an 8K display doesn't keep
     growing past that, avoiding oversized text on the largest panels.
     clamp() itself is the platform-detection-free answer to the
     original "auto-scale by browser platform" question: it reads actual
     viewport width, not a spoofable/unreliable UA string. */
  font-size: clamp(1rem, 0.679rem + 0.357vw, 1.25rem);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video, canvas { max-width: 100%; height: auto; display: block; }

a {
  color: var(--navy);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 0.2em;
}
a:hover { color: var(--ink); }
a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }

button {
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  cursor: pointer;
}
button:focus-visible { outline: none; box-shadow: var(--focus-ring); }

p, li, dd { max-width: var(--measure-prose); }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 580;
  font-variation-settings: "opsz" 32;
  line-height: 1.15;
  letter-spacing: -0.005em;
  margin: 0 0 var(--s-4);
  color: var(--ink);
  text-wrap: balance;
}
h1 { font-size: var(--text-2xl); }
@media (min-width: 1024px) { h1 { font-size: var(--text-3xl); } }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }
h4 { font-size: var(--text-md); }

/* ---- Utility -------------------------------------------------- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: var(--s-2);
  left: var(--s-2);
  background: var(--ink);
  color: var(--paper);
  padding: var(--s-3) var(--s-4);
  border-radius: 4px;
  font-weight: 700;
  z-index: 1000;
  transform: translateY(-200%);
  transition: transform 120ms ease-out;
}
.skip-link:focus { transform: translateY(0); }

/* ---- Stale banner --------------------------------------------- */
.stale-banner {
  background: var(--amber-bg);
  color: var(--ink);
  border-block: 2px solid var(--amber);
  padding: var(--s-3) var(--s-4);
  text-align: center;
  font-size: var(--text-sm);
}
.stale-banner strong { color: var(--amber); margin-right: var(--s-2); text-transform: uppercase; letter-spacing: 0.05em; }

/* ---- Masthead ------------------------------------------------- */
.masthead {
  padding: var(--s-3) var(--s-4) 0;
  transition: opacity 140ms ease, max-height 140ms ease, padding 140ms ease;
}
@media (min-width: 1024px) {
  .masthead { padding: var(--s-2) var(--s-4) 0; }
}
.masthead__inner {
  max-width: var(--measure-grid);
  margin: 0 auto;
  text-align: center;
}
.masthead__rule {
  height: 3px;
  background: var(--red);
  border: 0;
  margin: var(--s-2) 0;
}
.masthead__rule--top    { background: var(--red); height: 4px; }
.masthead__rule--bottom {
  height: 1px;
  background: var(--rule-strong);
  margin-top: var(--s-2);
}
.wordmark {
  display: inline-block;
  text-decoration: none;
  color: var(--red);
  padding: var(--s-2);
  border-radius: 4px;
}
.wordmark:hover { color: var(--red); }
.wordmark__title {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(2.4rem, 8vw + 0.25rem, 4rem);
  font-variation-settings: "opsz" 64, "wdth" 90;
  line-height: 1;
  letter-spacing: -0.025em;
  color: var(--red);
}
.wordmark__sub {
  display: block;
  font-family: var(--font-body);
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-md);
  color: var(--ink-muted);
  margin-top: var(--s-1);
  letter-spacing: 0.02em;
}
.masthead__folio {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-muted);
  margin: var(--s-2) 0 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-2);
}

/* ---- Lede ------------------------------------------------------ */
/* Tight on mobile, even tighter (and headline-only) on desktop. The
   wordmark + folio in the masthead already cover the "what is this"
   role; the lede doesn't need to take a full viewport on a laptop. */
.lede {
  padding: var(--s-4) var(--s-4) var(--s-5);
  background: var(--paper);
}
.lede__inner {
  max-width: 56ch;
  margin: 0 auto;
  text-align: center;
}
.lede__headline {
  font-family: var(--font-display);
  font-weight: 700;
  font-variation-settings: "opsz" 64;
  font-size: clamp(1.4rem, 3vw + 0.5rem, 2rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin-bottom: var(--s-2);
  color: var(--ink);
}
.lede__summary {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink-muted);
  margin: 0 auto;
}
@media (min-width: 1024px) {
  .wordmark__title { font-size: clamp(2rem, 3vw + 0.5rem, 2.7rem); }
  .wordmark__sub { font-size: var(--text-sm); }
}
/* (Dead .masthead.is-compact + .lede rules removed 2026-05-02 —
   the surfaces these target were deleted from the DOM long ago.) */

/* ---- Metro picker -------------------------------------------- */
.metro-picker {
  background: var(--paper-2);
  border-block: 1px solid var(--rule);
  padding: var(--s-2) var(--s-4);
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: blur(6px);
  transition: padding 140ms ease, background 140ms ease, box-shadow 140ms ease;
}
@supports not (backdrop-filter: blur(6px)) {
  .metro-picker { background: var(--paper-2); }
}
.metro-picker__inner {
  max-width: var(--measure-grid);
  margin: 0 auto;
}
/* Mobile: stack brand + dropdown + share vertically inside the bar
   with tight spacing. The bar is still sticky and ~120px tall on
   phones (brand row + dropdown row + share row). */
.metro-picker__inner {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  align-items: stretch;
}
@media (min-width: 1024px) {
  /* Desktop masthead width cap. The actual desktop LAYOUT (flex command
     bar) is defined in the unified masthead block near the end of this
     file (search "UNIFIED COMMAND BAR flex layout"). The old grid here
     (display:grid + 6 auto columns) was the failure-class layout and has
     been removed — only the width cap remains so both blocks agree. */
  .metro-picker { padding: var(--s-1) var(--s-4); }
  .metro-picker__inner {
    max-width: min(1240px, 100% - 2 * var(--s-4));
  }
}
/* The .metro-picker__brand rule lives further down, alongside the
   brand-name + brand-tagline children (v1.0.21 brand block). Keeping
   font-variation-settings off the parent anchor — Atkinson Hyperlegible
   doesn't support opsz/wdth axes and inheriting them onto the tagline
   child caused render artifacts in the sticky header. */
.metro-picker__brand:hover .metro-picker__brand-name { color: var(--red-deep); }
.metro-picker__heading {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-muted);
  margin: 0 0 var(--s-2);
  text-align: center;
}
@media (min-width: 1024px) {
  .metro-picker__heading {
    margin: 0;
    text-align: left;
    white-space: nowrap;
  }
}
/* Chip wall is hidden — the dropdown in the sticky bar is the primary
   metro picker on every breakpoint. The chip wall stays in the DOM
   for hash-routing keyboard nav but never shows. */
.metro-picker__chips { display: none; }

.metro-chip {
  min-height: var(--tap);
  padding: var(--badge-pad-y) var(--badge-pad-x);
  background: var(--paper);
  border: 2px solid var(--rule);
  border-radius: var(--badge-radius-pill);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--badge-font);
  color: var(--ink);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.1;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
@media (min-width: 1024px) {
  /* Single-line city pills on desktop — the anchor city sub-label
     gets dropped to halve the chip height. */
  .metro-chip {
    min-height: 32px;
    padding: var(--badge-pad-y) var(--badge-pad-x);
    font-size: var(--badge-font);
    border-width: 1px;
    white-space: nowrap;
  }
  .metro-chip__sub { display: none; }
}
.metro-chip__name { display: block; }
.metro-chip__sub {
  display: block;
  font-weight: 400;
  font-size: var(--badge-font);
  color: var(--ink-muted);
  margin-top: 2px;
}
.metro-chip:hover { border-color: var(--ink); }
.metro-chip[data-active="true"] {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.metro-chip[data-active="true"] .metro-chip__sub { color: var(--paper-3); }

/* Masthead control chrome is consolidated in the unified masthead
   block near the end of the file. */

/* (Dead .metro-picker.is-compact rules removed 2026-05-02 — the
   IntersectionObserver that toggled this class observed .masthead /
   .lede surfaces that no longer exist in the DOM, so the class was
   never set. Per Codex MED.) */

/* ---- Metro panel --------------------------------------------- */
.metro-panel {
  padding: var(--s-5) var(--s-4);
  outline: none;
}
.metro-panel:focus-visible { box-shadow: none; }

.loading,
.empty {
  text-align: center;
  padding: var(--s-7) var(--s-4);
  color: var(--ink-muted);
  font-style: italic;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14;
  font-size: var(--text-md);
}
.empty--error { color: var(--red); }

/* ---- Metro briefing layout ----------------------------------- */
.metro-briefing {
  max-width: var(--measure-grid);
  margin: 0 auto;
  display: grid;
  gap: var(--s-5);
}
.metro-briefing__head { text-align: center; }
.metro-briefing__kicker {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--red);
  margin: 0 0 var(--s-2);
}
.metro-briefing__headline {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 96;
  font-weight: 700;
  font-size: clamp(1.6rem, 3vw + 0.8rem, 2.4rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin: 0;
}
.metro-briefing__location {
  font-family: var(--font-display);
  font-style: italic;
  font-variation-settings: "opsz" 14;
  color: var(--ink-2);
  margin-top: var(--s-2);
  font-size: var(--text-base);
}

/* ---- Stat band ------------------------------------------------ */
.stat-band {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--badge-radius-tag);
  padding: var(--badge-pad-y) var(--badge-pad-x);
}
.stat-band__heading {
  /* Visible now — carries the metro label so readers don't mistake
     these counts for statewide totals. */
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink);
  margin: 0 0 var(--s-3);
  text-align: center;
}
.stat-band__metro {
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--red-deep);
  text-transform: none;
}

/* Stat grid — 2 columns on every breakpoint, compressed. Each tile
   stays a horizontal-flex row (small label left, big numeral right). */
.stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-1);
}

.stat-tile {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: var(--s-1) var(--s-2);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  min-height: 36px;
}
.stat-tile__label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ink);
  margin: 0;
  line-height: 1.2;
  flex: 1;
  min-width: 0;
}
.stat-tile__value {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 64;
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1;
  margin: 0;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  flex: 0 0 auto;
}

/* Stat-tile color stripes — aligned with the jump-nav HEALTH/LICENSE
   grouping. HEALTH (inspection / sanitation) = red; LICENSE
   (administrative / regulatory) = navy; positive subsets (clean
   plates, new licenses) = green. Reader scanning the stat band
   should clump the same way they scan the jump nav. */
/* HEALTH group — red border */
/* 5-bucket UX color scheme: red (UEO) / yellow (Near Miss) /
   red-deep (chronic) / green (clean) / blue (admin) / black (death). */
.stat-tile--under-emergency-order { border-left: 6px solid var(--dim-red-alert); }
.stat-tile--recent-failures      { border-left: 6px solid var(--dim-near-miss); }
.stat-tile--worst-offenders      { border-left: 6px solid var(--dim-worst-offenders); }
.stat-tile--bad-actors           { border-left: 6px solid var(--dim-worst-offenders); }
.stat-tile--most-improved        { border-left: 6px solid var(--dim-most-improved); }
/* LICENSE group — navy border */
.stat-tile--permanent-closures   { border-left: 6px solid var(--dim-closures); }
.stat-tile--lost-licenses        { border-left: 6px solid var(--dim-owner-changed); }
/* Positive signals (good news) — green border, regardless of group */
.stat-tile--openings             { border-left: 6px solid var(--dim-openings); }
.stat-tile--new-licenses         { border-left: 6px solid var(--dim-openings); }
/* clean_plates accent declared once with the dimension below — green */

.stat-help {
  margin: var(--s-5) auto 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
  max-width: 65ch;
  line-height: 1.55;
  text-align: left;
}

/* ---- Briefing prose ------------------------------------------ */
.briefing {
  max-width: var(--measure-prose);
  margin: 0 auto;
}
.briefing__prose p { margin: 0 0 var(--s-4); }
.briefing__paragraph {
  /* Lede + briefing prose paragraphs match the per-dim narrative
     size (text-base / 18px font-body) per operator 2026-05-02:
     "intro narration font size is very big. reduce to the same size
     as sections". Was previously oversized on font-display at text-md.
     Body font is more readable for the 55+ audience anyway. */
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.65;
  color: var(--ink);
  max-width: 75ch;
}
/* Drop cap on the lede paragraph. Only applied when the paragraph
   isn't first-letter punctuation/quote (CSS ::first-letter would
   otherwise enlarge the quote glyph instead of the actual letter,
   producing a typographic glitch). The `data-leading-letter` flag is
   set in JS only when the first character is a letter (Unicode L).
   Suppressed when the briefing renders a persona avatar — the
   avatar IS the drop-cap. */
.briefing__paragraph--first[data-leading-letter="true"]::first-letter {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 96;
  font-weight: 700;
  font-size: 2.6em;
  line-height: 0.9;
  float: left;
  padding: 0.05em var(--s-3) 0 0;
  color: var(--red);
}
.briefing__prose[data-has-avatar="true"]
  .briefing__paragraph--first[data-leading-letter="true"]::first-letter {
  font-size: inherit;
  font-family: inherit;
  font-weight: inherit;
  float: none;
  padding: 0;
  color: inherit;
}

/* Persona avatar acting as a portrait drop-cap on the briefing prose.
   Floats left so the lede prose flows around it, exactly as a drop
   cap would. Sized for visibility (matches the ~4em CSS drop-cap
   block height). Square crop with sharp edge — no rounded corners,
   keeps the newspaper register. */
.briefing__avatar {
  float: left;
  width: 5.5em;
  height: 5.5em;
  margin: 0.2em var(--s-3) var(--s-1) 0;
  object-fit: cover;
  object-position: center top;
  border: 2px solid var(--ink);
  background: var(--paper-2);
  shape-outside: margin-box;
}
@media (max-width: 480px) {
  .briefing__avatar {
    width: 4.5em;
    height: 4.5em;
    margin-right: var(--s-2);
  }
}
.briefing__byline {
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  text-align: right;
  margin-top: var(--s-4);
}

/* Briefing dimension sections — each paragraph wrapped in a themed box
   so closure / ownership / chronic / clean-plates / etc. read as
   visually distinct blocks instead of a continuous prose stream. The
   left border + kicker label echo the matching dimension panel below
   for at-a-glance grouping. Click the kicker to jump to the section. */
.briefing-section {
  border-left: 4px solid var(--rule);
  padding: var(--s-2) 0 var(--s-2) var(--s-3);
  margin-bottom: var(--s-3);
}
.briefing-section:last-child { margin-bottom: 0; }
.briefing-section__kicker {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-muted);
  text-decoration: none;
  margin-bottom: var(--s-1);
  padding: 1px 0;
  border-bottom: 1px dotted transparent;
}
.briefing-section__kicker:hover,
.briefing-section__kicker:focus-visible {
  color: var(--ink);
  border-bottom-color: currentColor;
}
.briefing-section__kicker:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
}
.briefing-section .briefing__paragraph { margin: 0; }
/* Per-dimension theme — five-bucket UX color scheme:
     RED    = Red Alert (UEO)             — DBPR-shut-down severity
     RED-D  = chronic (worst, bad-actors) — repeating offenders
     YELLOW = Near Miss (recent_failures) — cited but not closed
     GREEN  = Clean Plates                — winners
     BLUE   = Administrative (lost / new / license-activity)
     BLACK  = Closed / Ghost (permanent_closures)
     NEUTRAL = statewide context, velocity (frame, not signal) */

/* Operator 2026-05-04 — single canonical palette per dim. Sections
   are paper-white with a single solid-color band on the LEFT and the
   kicker text in the same dim hex. No tinted backgrounds (operator:
   "worst of worst is pink" — the tinted fill was reading as the dim
   color, washing out the band). The dim color shows up ONLY on the
   border-left band + kicker text + dim icon. Hex values match
   config/dimensions.json. */
.briefing-section--statewide-context {
  border-left-color: #64748b;
  background: var(--paper);
}
.briefing-section--statewide-context .briefing-section__kicker { color: #64748b; }

.briefing-section--under-emergency-order { border-left-color: #dc2626; background: var(--paper); }
.briefing-section--under-emergency-order .briefing-section__kicker { color: #dc2626; }

.briefing-section--recent-failures { border-left-color: #F97316; background: var(--paper); }
.briefing-section--recent-failures .briefing-section__kicker { color: #F97316; }

.briefing-section--clean-plates { border-left-color: #16a34a; background: var(--paper); }
.briefing-section--clean-plates .briefing-section__kicker { color: #16a34a; }

.briefing-section--worst-offenders,
.briefing-section--bad-actors {
  border-left-color: #8B1818;
  background: var(--paper);
}
.briefing-section--worst-offenders .briefing-section__kicker,
.briefing-section--bad-actors .briefing-section__kicker { color: #8B1818; }

/* Operator 2026-05-04 (rev 2): WORSTS = SUNBURST ORANGE — distinct
   from chronic-bad-actors red, distinct from the standard near-miss
   orange (#F97316), and bright enough to read as the cross-flag
   "extreme" tier. */
.briefing-section--worsts {
  border-left-color: #ff5722;
  background: var(--paper);
}
.briefing-section--worsts .briefing-section__kicker { color: #ff5722; }

.briefing-section--most-improved { border-left-color: #16a34a; background: var(--paper); }
.briefing-section--most-improved .briefing-section__kicker { color: #16a34a; }

.briefing-section--permanent-closures,
.briefing-section--closures {
  border-left-color: #6B5B4E;
  background: var(--paper);
}
.briefing-section--permanent-closures .briefing-section__kicker,
.briefing-section--closures .briefing-section__kicker { color: #6B5B4E; }

.briefing-section--ghost-licenses { border-left-color: #64748b; background: var(--paper); }
.briefing-section--ghost-licenses .briefing-section__kicker { color: #64748b; }

.briefing-section--lost-licenses { border-left-color: #1A3D6D; background: var(--paper); }
.briefing-section--lost-licenses .briefing-section__kicker { color: #1A3D6D; }

.briefing-section--openings,
.briefing-section--new-licenses {
  border-left-color: #06b6d4;
  background: var(--paper);
}
.briefing-section--openings .briefing-section__kicker,
.briefing-section--new-licenses .briefing-section__kicker { color: #06b6d4; }

.briefing-section--license-activity { border-left-color: #1A3D6D; background: var(--paper); }
.briefing-section--license-activity .briefing-section__kicker { color: #1A3D6D; }

.briefing-section--chain-activity { border-left-color: #9333ea; background: var(--paper); }
.briefing-section--chain-activity .briefing-section__kicker { color: #9333ea; }

.briefing-section--velocity {
  border-left-color: var(--ink-muted);
  background: var(--paper);
}
.briefing-section--velocity .briefing-section__kicker { color: var(--ink-2); }
/* In-briefing inline links (briefing-mention pills inherit their own
   colors elsewhere; this catches plain anchors like the kicker plus
   any future inline citations in prose). */
.briefing-section a:not(.briefing-section__kicker):not(.briefing-mention) {
  color: var(--navy);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* ---- Dimensions ---------------------------------------------- */
/* Single-column stack at every breakpoint. Each dimension section is a
   sequential block — sequential reading is the design language. */
.dimensions {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}
.dimension { display: flex; flex-direction: column; gap: var(--s-4); }
.dimension__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  border-bottom: 2px solid var(--ink);
  padding-bottom: var(--s-2);
}
.dimension__heading { margin: 0; font-size: var(--text-md); }
.dimension__count {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

/* Expand/collapse cue — gives <summary> a clear "click to expand"
   affordance with chevron. The default disclosure triangle is hidden
   in our CSS reset; this is the visible substitute. The state cue
   ("Show N records" / "Hide N records") swaps via the [open]
   attribute on the parent <details>. */
.dimension__expand {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 6px 10px;
  white-space: nowrap;
  transition: background 120ms, border-color 120ms;
  margin-left: auto;
}
.dimension > summary.dimension__head:hover .dimension__expand,
.dimension > summary.dimension__head:focus-visible .dimension__expand {
  background: var(--paper);
  border-color: var(--ink);
}
.dimension__expand-cue { display: inline-block; }
.dimension__expand-cue--open { display: none; }
.dimension[open] .dimension__expand-cue--closed { display: none; }
.dimension[open] .dimension__expand-cue--open { display: inline-block; }
.dimension__expand-chevron {
  transition: transform 200ms ease;
  flex-shrink: 0;
}
.dimension[open] .dimension__expand-chevron {
  transform: rotate(180deg);
}
@media (prefers-reduced-motion: reduce) {
  .dimension__expand-chevron { transition: none; }
}
/* Hide the default browser disclosure triangle on the summary so our
   chevron is the canonical affordance. */
.dimension > summary.dimension__head { list-style: none; cursor: pointer; }
.dimension > summary.dimension__head::-webkit-details-marker { display: none; }
/* The legacy .dimension__count pill stays visible as a secondary
   cue; expand button is the primary affordance. Hide the count when
   the expand button is present (avoids two redundant indicators). */
.dimension__head .dimension__expand + .dimension__count,
.dimension__head .dimension__count + .dimension__expand { /* preserve order tolerance */ }
.dimension__head:has(.dimension__expand) .dimension__count { display: none; }

/* Section heading borders use the same 5-bucket color scheme. */
/* Canonical per-dim palette from config/dimensions.json — operator
   2026-05-04: "JUMP BUTTON COLORS = DIMENSION BAR COLORS = DIMENSION
   COLORS IN BLOGS". Same hex codes everywhere. */
.dimension--under-emergency-order .dimension__head { border-bottom-color: #dc2626; }
.dimension--recent-failures       .dimension__head { border-bottom-color: #F97316; }
.dimension--worst-offenders       .dimension__head { border-bottom-color: #8B1818; }
.dimension--bad-actors            .dimension__head { border-bottom-color: #8B1818; }
.dimension--worsts                .dimension__head { border-bottom-color: #ff5722; }
.dimension--most-improved         .dimension__head { border-bottom-color: #16a34a; }
.dimension--clean-plates          .dimension__head { border-bottom-color: #16a34a; }
.dimension--permanent-closures    .dimension__head { border-bottom-color: #6B5B4E; }
.dimension--closures              .dimension__head { border-bottom-color: #6B5B4E; }
.dimension--ghost-licenses        .dimension__head { border-bottom-color: #64748b; }
.dimension--lost-licenses         .dimension__head { border-bottom-color: #1A3D6D; }
.dimension--openings              .dimension__head { border-bottom-color: #06b6d4; }
.dimension--new-licenses          .dimension__head { border-bottom-color: #06b6d4; }
.dimension--chain-activity        .dimension__head { border-bottom-color: #9333ea; }

/* Per-section explainer that appears beneath the section heading when the
   accordion is open. Sized for 55+ readability — body-text sized, full
   ink contrast, roman (not italic), generous line-height, capped measure
   so lines stay under ~75ch. */
.dimension__intro {
  margin: var(--s-2) 0 var(--s-3);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--ink);
  font-style: normal;
  border-left: 3px solid var(--rule);
  padding: var(--s-2) var(--s-3);
  background: var(--paper-2);
  max-width: 75ch;
}
.dimension__intro ol,
.dimension__intro ul {
  margin: var(--s-2) 0 0;
  padding-left: var(--s-4);
}
.dimension__intro li {
  margin-bottom: var(--s-1);
  line-height: 1.55;
}
.dimension__intro li:last-child { margin-bottom: 0; }
.dimension__intro p { margin: 0 0 var(--s-2); }
.dimension__intro p:last-child { margin-bottom: 0; }
.dimension__intro-method-link {
  color: var(--teal, #063f5c);
  font-weight: 700;
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  white-space: nowrap;
}
.dimension__intro-method-link:hover,
.dimension__intro-method-link:focus-visible {
  text-decoration-style: solid;
}

/* Cross-panel notes that go below the dimensions block — small,
   secondary, talks about overlap + dedup rules. */
.dimensions__notes {
  margin: var(--s-4) 0 0;
  padding: var(--s-3) var(--s-4);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 6px;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--ink-muted);
}

/* Same per-signal accent on stat tiles */
.stat-tile--clean-plates       { border-left: 6px solid var(--dim-clean-plates); }

/* ---- Card stack ---------------------------------------------- */
.card-stack { display: grid; gap: var(--s-4); }
.more-cards { margin-top: var(--s-4); }
.more-cards__summary {
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--navy);
  padding: var(--s-3) var(--s-4);
  border: 2px solid var(--navy);
  border-radius: 6px;
  background: var(--navy-bg);
  list-style: none;
  text-align: center;
  min-height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
}
.more-cards__summary::-webkit-details-marker { display: none; }
.more-cards__summary:hover { background: var(--navy); color: var(--paper); }
.more-cards__summary:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.more-cards[open] .more-cards__summary { margin-bottom: var(--s-4); }
.more-cards__list { display: grid; gap: var(--s-4); }
.more-cards__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  width: 100%;
  margin-top: var(--s-4);
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--navy);
  padding: var(--s-3) var(--s-4);
  border: 2px solid var(--navy);
  border-radius: 6px;
  background: var(--navy-bg);
  min-height: var(--tap);
}
.more-cards__btn:hover { background: var(--navy); color: var(--paper); }
.more-cards__btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.more-cards__remaining {
  font-weight: 400;
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}
.more-cards__btn:hover .more-cards__remaining { color: var(--paper-3); }

/* ---- Restaurant card -----------------------------------------
   Cards are one reading flow at every viewport. Metadata sits above the
   content when present; a window resize must never revive a side rail or a
   second grid track that creates blank space beside the evidence. */
/* One quiet perimeter separates adjacent cards on both the desktop grid and
   the single-column mobile stack. The older treatment drew several competing
   rings; this is intentionally just one neutral boundary, with the existing
   left spine still available for section identity. */
.card {
  background: var(--paper-2);
  border: 1px solid #cbd5e1;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
  border-radius: 8px;
  padding: var(--s-3);
  display: block;
  position: relative;
  /* Skip layout+paint for cards that are off-screen. A metro page renders
     hundreds of these, and auto-paging now appends more as the reader scrolls,
     so without this the cost of the page grows with the number of cards LOADED
     rather than the number VISIBLE. Same idiom already proven on
     .fri-news-item (templates/fri/news.html.j2).

     `auto` in contain-intrinsic-size is the important half: the browser stores
     each card's REAL rendered size after it is first displayed and reuses it
     while the card is skipped, so the scrollbar stops jumping the way a fixed
     placeholder height makes it jump. 320px is only the first guess, used
     before a card has ever been rendered.

     320px is an UNMEASURED first guess -- no browser was available to measure a
     real card. That is deliberate rather than sloppy: the `auto` keyword means
     a wrong guess self-corrects per card the first time it renders, so the cost
     is bounded to first paint. If cards are ever measured, replace it.

     Known trade-off, raised in review: while cards below the viewport have
     never been rendered they each reserve the guess, so the SCROLLBAR is
     inaccurate until the reader scrolls through them. That is the standard
     content-visibility bargain and is what `auto` damps. It does NOT mis-time
     auto-paging: the sentinel is a real element at the end of the stack, not a
     scroll-offset estimate, and the cards between the viewport and it render
     (correcting their heights) as the reader approaches.

     Safe against the clipping trap recorded at .card-trend below: paint
     containment applies only while the card is off-screen and not
     user-relevant, and nothing currently opens outside the card box (the
     popover that did was removed 2026-08-06, and negative-offset descendants
     were checked -- there are none). Unsupported browsers ignore both
     declarations and render exactly as before. */
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;
}
@media (max-width: 540px) {
  /* Narrow cards keep their classification metadata in normal flow so
     the risk-card header can stack the name and dimension badges. */
  .card {
    display: block;
  }
  .card__meta {
    flex-direction: row !important;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start !important;
    gap: var(--s-2) !important;
    margin: 0 0 var(--s-1) 0;
    min-width: 0;
  }
}
.card__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: flex-start;
  gap: var(--s-2);
  min-width: 80px;
  margin: 0;
}

.risk-card-header{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:.5rem .75rem;}
.risk-card-title{margin:0;font-size:1.32rem;font-weight:800;line-height:1.2;color:var(--ink,#000);overflow-wrap:anywhere;hyphens:auto;}
.risk-card-title a{color:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.15em;}
.risk-card-badges{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:.25rem;margin:0;padding: var(--badge-pad-y) var(--badge-pad-x);list-style:none;}
.dimension-badge{padding: var(--badge-pad-y) var(--badge-pad-x);border:1px solid var(--ink,#000);border-radius: var(--badge-radius-pill);font-size: var(--badge-font);font-weight:700;line-height:1.1;letter-spacing:.03em;text-transform:uppercase;white-space:normal;text-align:center;}
@media (max-width:549px){.risk-card-header{grid-template-columns:1fr;}.risk-card-badges{justify-content:flex-start;}}
.risk-card-header > .card__location,
.risk-card-header > .card__cuisine {
  grid-column: 1 / -1;
}

/* Section chip — small pill in the right rail labeling which
   dimension this card belongs to ("Near Miss", "Chronic", etc.).
   Color-keyed by dim group: health (red family), license (navy),
   clean-plates (green). */
.card__section {
  display: inline-flex;
  align-items: center;
  padding: 3px var(--s-2);
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--ink);
  color: var(--paper);
}
.card__section--under-emergency-order { background: #dc2626; color: var(--paper); }
.card__section--recent-failures       { background: #F97316; color: var(--paper); }
.card__section--worst-offenders       { background: #8B1818; color: var(--paper); }
.card__section--bad-actors            { background: #8B1818; color: var(--paper); }
.card__section--most-improved         { background: #16a34a; color: var(--paper); }
.card__section--clean-plates          { background: #16a34a; color: var(--paper); }
.card__section--permanent-closures    { background: #6B5B4E; color: var(--paper); border: 1px solid #6B5B4E; }
.card__section--lost-licenses         { background: #1A3D6D; color: var(--paper); }
.card__section--openings              { background: #06b6d4; color: var(--paper); }
.card__section--new-licenses          { background: #06b6d4; color: var(--paper); }
.dimension-badge.card__section,
.dimension-badge.risk-band,
.dimension-badge.callback-overdue {
  border-radius: var(--badge-radius-pill);
  font-size: var(--badge-font);
  line-height: 1.1;
  letter-spacing: .03em;
  white-space: normal;
  text-align: center;
}

/* Inspection letter grade chip — A/B/C/D/F derived from the inspection
   that earned the dimension entry. It is placed with the trend/inspection
   signal, not in a separate card-top metadata rail. */
.card__letter {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 38px;
  padding: 2px 8px;
  border-radius: 4px;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 96;
  font-weight: 800;
  font-size: 1.4rem;
  line-height: 1;
  border: 2px solid currentColor;
  background: var(--paper);
  font-variant-numeric: normal;
  letter-spacing: 0;
}
/* "Violation grade" micro-label (operator 2026-06-21, win #4) — sits above
   the letter so a RiskyEats-derived grade can never read as an official DBPR
   venue letter grade. Tiny, uppercase, no display-font weight. */
.card__letter-microlabel {
  display: block;
  font-family: var(--font-body, inherit);
  font-variation-settings: normal;
  font-weight: 600;
  font-size: 0.42rem;
  line-height: 1.05;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0.85;
  margin-bottom: 1px;
}
.card__letter--low      { color: var(--green); }
.card__letter--moderate { color: var(--amber); }
.card__letter--high     { color: var(--red); }
.card__letter--critical {
  color: var(--paper);
  background: var(--red-deep);
  border-color: var(--red-deep);
}
.card__letter--unrated {
  color: var(--ink-muted);
  border-color: var(--rule);
  background: var(--paper-2);
}

/* Bottom-row actions — closure-history expander, all-violations
   expander, and the report-issue link sit on one line at desktop
   widths so the card foot reads tight. Wraps to multi-row on
   narrow viewports. Per operator 2026-05-02. */
.card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-4);
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
}
.card__actions > * { margin: 0; }
.card__actions .card__details {
  flex: 0 0 auto;
}
.card__actions .card__report {
  flex: 0 1 auto;
  margin-left: auto;        /* push to the right end of the row */
}
.card__actions .card__report-link {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.card__actions .card__report-link:hover { color: var(--red); }

/* =================================================================
   Per-card share buttons — Operator 2026-05-05: requires credit
   when readers share our data. Direct intents to FB/X/LinkedIn/
   Reddit/Email + clipboard copy. Sized small to fit card actions
   row without crowding "Report issue" link.
   ================================================================= */
/* Share is a <details> now (operator 2026-08-11 declutter): only the
   "Share" summary chip renders per card; the icon row appears on open.
   display:flex would hide <details>'s open/closed semantics in some
   engines, so the OPEN state uses inline-flex on the buttons instead. */
.card__share {
  flex: 0 1 auto;
  margin-left: auto;
  font-size: var(--text-sm);
  order: 99;
}
.card__share[open] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1, 4px);
}
.card__share-label {
  cursor: pointer;
  list-style: none;
  user-select: none;
  margin-right: var(--s-1, 4px);
  color: var(--ink-muted);
  font-size: var(--text-xs, .72rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .04em;
}
.card__share-label::-webkit-details-marker { display: none; }
.card__share-label::marker { content: ""; }
.card__share-label::before { content: "↗ "; opacity: .7; }
.card__share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 26px -> 30px (operator 2026-08-21, mobile copy-density audit).
     Smaller bump than the other icon buttons on this pass: five of
     these render in a row per card (fb/tw/li/rd/em), so a bigger jump
     risks crowding/wrapping that a single header icon doesn't. */
  width: 30px;
  height: 30px;
  padding: 0;
  color: #fff;
  text-decoration: none;
  font-weight: 900;
  font-size: .82rem;
  line-height: 1;
  border-radius: 4px;
  border: 0;
  cursor: pointer;
}
.card__share-btn:hover { opacity: .85; }
.card__share-btn--fb { background: #1877f2; }
.card__share-btn--tw { background: #000; }
.card__share-btn--li { background: #0a66c2; }
.card__share-btn--rd { background: #ff4500; }
.card__share-btn--em { background: #4b5563; }
.card__share-btn--cp { background: #6b7280; }
@media (max-width: 540px) {
  .card__share {
    width: 100%;
    margin-left: 0;
    margin-top: var(--s-1, 4px);
    padding-top: var(--s-1, 4px);
    border-top: 1px dashed var(--rule);
  }
}

/* =================================================================
   Worst Today hero rail — 3-card "what's risky right now" strip
   above the dimensions block. Pulled from the highest-urgency dims
   (Red Alert → Near Miss → Chronic Offenders), one tile each, no
   duplicates. Tapping a tile jumps to that card's anchor.
   ================================================================= */
.hero-rail {
  margin: 0 0 var(--s-5);
  padding: var(--s-3) 0 var(--s-4);
  border-block: 2px solid var(--ink);
}
.hero-rail__head {
  margin: 0 0 var(--s-3);
}
.hero-rail__title {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 96;
  font-weight: 700;
  font-size: var(--text-md);
  margin: 0;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.hero-rail__sub {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin: var(--s-1) 0 0;
}
.hero-rail__tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--s-3);
}
.hero-rail__tile {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto auto auto;
  grid-template-areas:
    "kicker letter"
    "name   letter"
    "city   letter"
    "score  score";
  gap: 2px var(--s-2);
  padding: var(--s-3);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-left: 6px solid var(--ink);
  border-radius: 6px;
  text-decoration: none;
  color: var(--ink);
  transition: box-shadow 120ms ease, transform 120ms ease;
}
.hero-rail__tile:hover,
.hero-rail__tile:focus-visible {
  box-shadow: 0 4px 12px rgba(17, 17, 17, 0.12);
  transform: translateY(-1px);
}
.hero-rail__tile--low      { border-left-color: var(--green); }
.hero-rail__tile--moderate { border-left-color: var(--amber); }
.hero-rail__tile--high     { border-left-color: var(--red); }
.hero-rail__tile--critical { border-left-color: var(--red-deep); }
/* The risk rail carries three different kinds of urgency. Preserve the
   severity stripe, but give each source its own field so an emergency order,
   a near miss, and a systemic pattern do not collapse into one red block. */
.hero-rail__tile[data-dim="under-emergency-order"] { background: #fff1f2; }
.hero-rail__tile[data-dim="recent-failures"]       { background: #fff7ed; }
.hero-rail__tile[data-dim="bad-actors"]            { background: #fdf4ff; }
.hero-rail__kicker {
  grid-area: kicker;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
}
.hero-rail__letter {
  grid-area: letter;
  align-self: center;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 96;
  font-weight: 800;
  font-size: 2.4rem;
  line-height: 1;
  border: 2px solid currentColor;
  border-radius: 6px;
  padding: 4px 10px;
  min-width: 48px;
  text-align: center;
}
.hero-rail__tile--low      .hero-rail__letter { color: var(--green); }
.hero-rail__tile--moderate .hero-rail__letter { color: var(--amber); }
.hero-rail__tile--high     .hero-rail__letter { color: var(--red); }
.hero-rail__tile--critical .hero-rail__letter {
  color: var(--paper);
  background: var(--red-deep);
  border-color: var(--red-deep);
}
.hero-rail__name {
  grid-area: name;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 32;
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.15;
  color: var(--ink);
  text-transform: uppercase;
}
.hero-rail__city {
  grid-area: city;
  font-family: var(--font-body);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--ink-2);
}
.hero-rail__score {
  grid-area: score;
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
/* Neutral card spine. Severity is now communicated by the dedicated
   log-scaled severity bar, not by competing card-border colors. */
.card[data-risk-band] {
  border-left: 4px solid var(--rule);
}

.card__head { display: flex; flex-direction: column; gap: var(--s-1); }
.card__name {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 32;
  font-weight: 700;
  font-size: 1.32rem;
  margin: 0;
  line-height: 1.2;
  color: var(--ink);
}
.card__location {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 0;
  font-style: italic;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 14;
}
.card__stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin: 0;
}
.card__stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.card__stat dt {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
}
.card__stat dd {
  /* SPACING 2026-08-05: was inline flow, so the gaps between a status pill, an
     EOS pill and the figure after them came from literal whitespace in the
     template, and the pieces wrapped anywhere. Flex gives one gap value and a
     shared baseline between a pill and the text beside it. */
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px var(--s-1);
  margin: 0;
  font-size: var(--text-base);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.card__note-provenance {
  display: block;
  margin-top: 3px;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-style: italic;
}
.risk-band {
  display: inline-block;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-tag);
  font-weight: 700;
  font-size: var(--badge-font);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border: 1px solid currentColor;
}
.risk-band--low      { color: var(--green); background: var(--green-bg); }
.risk-band--moderate { color: var(--amber); background: var(--amber-bg); }
.risk-band--high     { color: var(--red);   background: var(--red-bg); }
.risk-band--critical { color: var(--paper); background: var(--red); border-color: var(--red); }

.risk-score {
  /* This reads "5d since order" and was breaking after "5d", orphaning
     "since order" onto its own line. Spacing now comes from the value row's
     flex gap rather than a margin that inline flow could collapse. */
  white-space: nowrap;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Trend block — a STACKED block, not an inline pill (operator, 2026-08-07:
   "the actual badge that shows trends is tiny, so it wont be noticed").
   It was inline-flex at --text-xs tucked beside the other chips, which is what
   made it disappear. Three stacked lines, left-aligned, reading as a small
   statement: direction, movement, history. The leading rule in currentColor
   ties the block to its tone without relying on colour to carry meaning. */
.card-trend {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  margin: var(--s-2) 0 0;
  padding: 6px 10px;
  border: 1px solid currentColor;
  border-left-width: 3px;
  border-radius: 4px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1.3;
  /* NOT nowrap: the movement line is a sentence now and must wrap on a narrow
     card rather than force the block wider than its column. */
}
.card-trend--up {
  color: var(--red-deep);
  background: var(--red-bg);
}
.card-trend--down {
  color: var(--green);
  background: var(--green-bg);
}
.card-trend--flat {
  color: var(--ink-2);
  background: var(--paper-2);
}
.card-trend--snapshot {
  color: var(--ink-2);
  background: var(--paper-2);
}
/* Two states that are NOT points on the up/down scale (operator 2026-08-08).
   An active order is the strongest red on the card: the count fell because the
   venue was shut, so the arithmetic that produces "improving" is measuring the
   closure. A REOPENED venue is deliberately a step down from that in yellow --
   "go from red to a different color, like yellow" -- because the order was
   lifted and the venue is open, but the only inspection since is the callback
   that permitted the reopening, which the callback-complied badge already
   reports beside the reopen date. Green would present that one fact twice and
   let the second copy read as independent evidence. */
.card-trend--emergency {
  color: var(--red-deep);
  background: var(--red-bg);
  font-weight: 700;
}
.card-trend--reopened {
  color: #78350f;
  background: #fffbeb;
  border: 1px solid #f59e0b;
}
/* Line 1 — the headline fact. Direction is stated by the arrow AND the word,
   so it survives being read in monochrome or by a colour-blind reader. */
.card-trend__head {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 700;
  letter-spacing: 0.04em;
}
.card-trend__head > .methodology-link {
  color: inherit;
  text-decoration: none;
}
.card-trend__trend-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.card-trend__head > .methodology-link:focus-visible {
  outline: 3px solid var(--focus-ring-color, #0f172a);
  outline-offset: 2px;
}
.card-trend__arrow {
  font-size: 1.1em;
  line-height: 1;
}
.card-trend__dir {
  font-size: var(--text-sm);
}
.card-trend__grade {
  display: inline-flex;
  align-self: stretch;
  margin-left: auto;
}
.card-trend__grade .card__letter {
  min-width: 48px;
  height: auto;
  padding-inline: 9px;
  background: var(--paper);
}
.card-trend__grade > .methodology-link {
  display: inline-flex;
  color: inherit;
  text-decoration: none;
}
.card-trend__grade > .methodology-link:focus-visible {
  outline: 3px solid var(--focus-ring-color, #0f172a);
  outline-offset: 2px;
}
/* Critical (F) inside ANY trend block, not just direction=emergency.
   The .card-trend__grade .card__letter rule above forces background to
   --paper, but --critical's color stays --paper too — an invisible
   white-on-white letter (the "empty grade box" on live EO cards whose
   payload trend direction was down/flat). Restate the readable pair at
   the same 0,2,0+ specificity for every trend direction. */
.card-trend__grade .card__letter--critical {
  color: var(--red-deep);
  background: var(--paper);
  border-color: currentColor;
}
/* Line 2 — the numbers, carrying their own unit so "28 → 0" is not jargon. */
.card-trend__movement {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-1, currentColor);
}
/* "Slipping" — this venue just broke its own record, not a threshold.
   Rides inside the trend head beside the direction rather than becoming its
   own badge row: it is a reading of the same history the block already
   reports, and it is ADDITIVE (a venue can be WORSENING and slipping). It
   never appears beside IMPROVING -- the producer refuses that pair, because
   the two are the same comparison with opposite signs.
   Deliberately quieter than the direction it sits next to: the direction is
   the headline, this is the qualifier that says the headline is unusual. */
.card-trend__slipping {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--amber-rule, #B45309);
  color: var(--amber-deep, #92400E);
  background: var(--amber-wash, #FFFBEB);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
/* The arithmetic, in the reader's reach so the claim is checkable against the
   inspection list on the same page. Tabular so the two numbers line up. */
.card-trend__slipping-detail {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}
@media (max-width: 540px) {
  /* The label carries the meaning; the arithmetic is the supporting detail and
     is the first thing to go when the row cannot hold both. */
  .card-trend__slipping-detail { display: none; }
}
/* Line 3 — the history, with its orientation inline instead of in a legend. */
.card-trend__spark-row {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.card-trend__spark {
  display: inline-flex;
  align-items: end;
  gap: 2px;
  height: 20px;
}
.card-trend__bar {
  display: block;
  width: 4px;
  min-height: 2px;
  border-radius: 1px;
  background: currentColor;
  opacity: 0.72;
}
.card-trend__scale {
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--ink-2);
}

/* NO TOOLTIP AND NO EXPLANATION PARAGRAPH. This rule has survived two rounds
   of operator feedback and both lessons still apply.

   2026-08-06: the chip carried BOTH a native `title` tooltip and a CSS popover,
   so one hover produced two overlapping boxes; the popover was also clipped by
   `.card { overflow: hidden }` because it opened upward, outside the card.
   z-index cannot beat a clipping ancestor. Do not reintroduce a popover here.

   2026-08-07: the text-below-the-chip that replaced them was itself the
   problem -- three grey sentences defining an arrow, a number pair and a set
   of bars. The block above now states each of those in its own words, so there
   is nothing left to define. If a future change makes the block need a legend
   again, the block is wrong, not the legend missing. */
.card-trend { position: relative; }

/* Clean Plates medal legend — the ladder, with this metro's population on it.
   Sits under the dimension intro and above the cards, because it is the key to
   every badge below it AND the only place the full cohort size is legible: the
   homepage loads 24 cards of a metro that may hold hundreds. */
.grade-legend {
  margin: var(--s-2) 0 var(--s-3);
  padding: 10px 12px;
  border: 1px solid var(--rule, #e2e8f0);
  border-radius: 6px;
  background: var(--paper-2, #f8fafc);
}
.grade-legend__lead {
  margin: 0 0 8px;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--ink-2);
}
.grade-legend__lead strong {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--ink-1, inherit);
}
.grade-legend__list {
  display: grid;
  /* Four across on a wide viewport, collapsing to one column on a phone
     without a media query. */
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.grade-legend__item {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: baseline;
  gap: 3px 6px;
  padding: 7px 9px;
  border: 1px solid currentColor;
  border-left-width: 4px;
  border-radius: 4px;
}
.grade-legend__glyph { font-size: 1.05em; line-height: 1; }
.grade-legend__count {
  font-weight: 800;
  font-size: var(--text-md, 1.05rem);
  font-variant-numeric: tabular-nums;
}
.grade-legend__label {
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: 0.03em;
}
/* The criteria line spans the full row beneath the count, so the three short
   fields stay aligned across all four cells regardless of label width. */
.grade-legend__basis {
  grid-column: 1 / -1;
  font-size: var(--text-xs);
  font-weight: 400;
  line-height: 1.35;
  color: var(--ink-2);
}
/* An empty tier still renders -- "no venue here is that clean" is a finding.
   It recedes rather than disappearing, so the ladder keeps all four rungs. */
.grade-legend__item--empty { opacity: 0.55; }
.grade-legend__item--platinum { color: #4A5568; background: #EDF2F7; }
.grade-legend__item--gold     { color: #8A6D1F; background: #FEFCE8; }
.grade-legend__item--silver   { color: #5A6472; background: #F4F6F8; }
.grade-legend__item--bronze   { color: #8A5A2B; background: #FDF6EC; }

/* Clean Plates medal — the headline fact of the card, so it reads as an award
   rather than another chip in the row. Three parts on one line: the medal, the
   tier name, and what earned it, because a medal nobody can decode is
   decoration. The metal tone tints the disc and the rule; the SHAPE of the
   glyph and the written tier name carry the rank, so the ladder still reads in
   monochrome and for a colour-blind reader. */
.grade-medal {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  margin: 0 0 var(--s-2);
  padding: 5px 11px 5px 9px;
  border: 1px solid currentColor;
  border-left-width: 4px;
  border-radius: 4px;
  font-family: var(--font-body);
  line-height: 1.25;
  /* Wraps rather than forcing the card wider: the basis line is a phrase. */
  flex-wrap: wrap;
}
.grade-medal__disc {
  font-size: 1.15em;
  line-height: 1;
}
.grade-medal__label {
  font-weight: 800;
  font-size: var(--text-sm);
  letter-spacing: 0.04em;
}
.grade-medal__basis {
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--ink-2);
}
/* Metal tones. Deliberately muted -- this sits on a card that already carries a
   severity bar, and a saturated gold would outshout it. */
.grade-medal--platinum { color: #4A5568; background: #EDF2F7; }
.grade-medal--gold     { color: #8A6D1F; background: #FEFCE8; }
.grade-medal--silver   { color: #5A6472; background: #F4F6F8; }
.grade-medal--bronze   { color: #8A5A2B; background: #FDF6EC; }

.card__counts {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.card__counts strong { font-weight: 700; }
.card__disposition {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
}
/* Disposition scope label + date (operator 2026-06-21, wins #1/#6). The
   disposition is the LATEST DBPR visit, not the card's verdict — the label
   prefix ("Latest DBPR update:" / "Latest DBPR disposition:") and the
   trailing date make the chronology legible against the severity bar above
   (the trigger inspection). The --muted modifier guarantees a high-severity
   card's latest-visit line never renders as a green "all clear" verdict. */
.card__disposition-label {
  font-weight: 600;
  color: var(--ink-1, var(--ink-2));
}
.card__disposition-date {
  color: var(--ink-3, var(--ink-2));
  font-variant-numeric: tabular-nums;
}
.card__disposition--muted,
.card__disposition--muted .card__disposition-label,
.card__disposition--muted .card__disposition-date {
  color: var(--ink-3, #6b7280) !important;
  font-weight: 500;
}

/* One severity visualization per inspection-rooted card. The marker uses
   log10(score+1)/log10(500), so bottom-end differences remain visible
   while long-tail emergency scores still have room to move. */
.card__severity {
  margin: var(--s-2) 0 var(--s-1);
}
/* Signal-hierarchy eyebrows (operator 2026-06-21, win #5) — small tier
   labels that make the card's competing score-like signals legible as a
   ranked hierarchy rather than a flat contradictory pile: Primary = the
   RiskyEats Score bar; Secondary = the Violation grade badge; Context = the
   DBPR inspection-frequency tier; Latest = the disposition line. No signal
   removed — only labeled and grouped. */
.card__signal-eyebrow {
  margin: 0 0 4px;
  font-family: var(--font-body);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted, var(--ink-2));
}
.card__signal-eyebrow--primary {
  color: var(--severity-color, var(--ink-1));
}
.severity-bar-link {
  display: block;
  /* NO WIDTH CAP (operator 2026-08-16: "the heat bar scaling isnt working").
     The cap was removed from .severity-bar__svg on the same reasoning and the
     gauge still did not fill its card, because the cap that was actually
     binding lives HERE, on the ancestor: the svg is width:100% OF THIS BOX, so
     a 26rem parent pins the gauge at 416px no matter what the child says.
     Fixing the child alone changed nothing a reader could see. */
  width: 100%;
  color: inherit;
  text-decoration: none;
}
.severity-bar {
  --severity-color: #2e7d32;
  width: 100%;
}
.severity-bar--clean { --severity-color: #2e7d32; }
.severity-bar--routine { --severity-color: #fbc02d; }
.severity-bar--heavy { --severity-color: #f57c00; }
.severity-bar--severe { --severity-color: #d32f2f; }
.severity-bar--emergency { --severity-color: #4a148c; }
.severity-bar__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  margin-bottom: 16px;
  font-family: var(--font-body);
}
.severity-bar__title {
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.severity-bar__tier {
  color: var(--severity-color);
  font-size: var(--text-xs);
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Headline value (operator 2026-06-21, win #9) — the score + tier lead the
   bar so the verdict reads at a glance; "RiskyEats Score" drops to a small
   sub-caption and the 0-scale legend is subordinated below the track. */
.severity-bar__headline {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25em;
  color: var(--severity-color);
  font-family: var(--font-display, var(--font-body));
  font-weight: 800;
  line-height: 1;
}
.severity-bar__headline-score {
  font-size: 1.45rem;
  letter-spacing: 0;
}
.severity-bar__headline-tier {
  font-size: 0.95rem;
  letter-spacing: 0.02em;
}
.severity-bar__headline-sep { opacity: 0.6; }
.severity-bar__title--sub {
  font-size: 0.62rem;
  font-weight: 700;
  opacity: 0.85;
}
/* THE GAUGE IS ONE SVG (operator 2026-08-16). What was here -- a 14px track,
   a 16px absolutely-positioned marker, a floating score bubble and two
   edge-collision variants (--left / --right) -- is now geometry inside a
   viewBox, so the track, the dot and the number scale together with the card
   and stay sharp at any device pixel ratio.

   The reserved 26px top margin went with it: the number lives inside the
   viewBox now, so it cannot collide with the headline above the way the
   floating bubble did on every Trusted card. */
.severity-bar__svg {
  display: block;
  width: 100%;
  height: auto;
  /* NO max-width (operator 2026-08-16: "not scaling on a desktop to take up
     the white space, it should scale with the container"). It was capped at
     34rem on the reasoning that a status gauge should not become a banner --
     but on a wide card that left the bar stranded mid-row with white space
     beside it, and the point of moving to a viewBox was that the gauge tracks
     its container. It fills the card now, and the aspect ratio holds so the
     number and the marker grow with it. */
  margin-top: var(--s-2);
  overflow: visible;
}
.severity-bar__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 8px;
  margin-top: 5px;
  color: var(--ink-muted);
  font-family: var(--font-body);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.25;
  text-transform: uppercase;
}
/* Subordinate scale legend (operator 2026-06-21, win #9) — the full 0-scale
   stays present but visually recedes below the headline + track so it reads
   as a reference key, not a competing score. */
.severity-bar__legend--subordinate {
  font-size: 0.6rem;
  font-weight: 600;
  opacity: 0.7;
  margin-top: 6px;
}
/* The focus ring follows the gauge to its new element: the track it used to
   outline no longer exists, so this silently stopped drawing anything and the
   link had no visible focus state. */
.severity-bar-link:hover .severity-bar__svg,
.severity-bar-link:focus-visible .severity-bar__svg {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── Big Bet #1: UNIFY THE SCORE MODEL ──────────────────────────────────
   The card's at-a-glance verdict is now ONE thing: the RiskyEats Score +
   tier (the headline above), with a single reconciled DIRECTION chip and a
   statewide PERCENTILE chip as subordinate context. The two 50/50 score
   COMPONENTS and the formerly-competing numbers live in the collapsed
   "How this score is built" disclosure below. Regulatory context (DBPR
   frequency, violation grade) is visually demoted to an eyebrow group.
   No signal removed — only labeled, reordered, and grouped. */

/* Direction + percentile chips ride just under the score headline. */
.severity-bar__context {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 12px;
}
.direction-chip,
.score-percentile-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25em;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1.3;
  white-space: nowrap;
  text-transform: capitalize;
}
.direction-chip {
  border: 1px solid currentColor;
  background: var(--paper);
}
.direction-chip--up   { color: #b91c1c; }
.direction-chip--down { color: #15803d; }
.direction-chip--flat { color: var(--ink-muted, #6b7280); }
.direction-chip__arrow { font-weight: 800; }
.score-percentile-chip {
  color: var(--ink-muted, #6b7280);
  background: rgba(23, 23, 23, 0.05);
  border: 1px solid rgba(23, 23, 23, 0.12);
  text-transform: none;
}

/* SECONDARY layer — the two halves of the 50/50 blend, in a disclosure. */
.card__details--score-components {
  margin-top: var(--s-2);
}
.score-components {
  margin-top: var(--s-2);
  font-family: var(--font-body);
}
.score-components__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 4px 0;
  border-bottom: 1px dotted var(--rule, rgba(23, 23, 23, 0.12));
}
.score-components__name {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--ink-1, #1a1a1a);
}
.score-components__val {
  font-family: var(--font-display, var(--font-body));
  font-size: 0.95rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted, #4b5563);
}
.score-components__sub {
  margin: 2px 0 8px;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--ink-muted, #6b7280);
}
.score-components__note {
  margin: 8px 0 0;
  font-size: 0.74rem;
  line-height: 1.45;
  color: var(--ink-muted, #6b7280);
}

/* CONTEXT layer — regulatory-context group eyebrow demotes the DBPR
   inspection-frequency row so it never reads as a risk score. */
.card__context-eyebrow {
  display: block;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted, #9ca3af);
}
.card__stat--reg-context {
  opacity: 0.92;
}

/* Big Bet #10 — "How to read this score" inline drawer */
/* FLATTENING 2026-08-05: this disclosure sits inside an already-bordered card,
   so its own border made a box-in-a-box -- four separate box-painting rules for
   one widget. The summary row is boundary enough. */
.score-readme {
  margin-top: var(--s-2);
  border: 0;
  border-radius: 0;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(0,0,0,0.07);
}
.score-readme__toggle {
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  padding: var(--s-1) var(--s-2);
  min-height: var(--tap);
  background: transparent;   /* flattened: the card already supplies a surface */
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
  user-select: none;
}
.score-readme__toggle::-webkit-details-marker { display: none; }
.score-readme__toggle::before {
  content: "\2139";
  font-size: 0.9rem;
  line-height: 1;
}
/* right-side disclosure caret — explicit expand affordance */
.score-readme__toggle::after {
  content: "\25BE";
  margin-left: auto;
  font-size: 0.8rem;
  transition: transform 0.15s ease;
}
.score-readme[open] .score-readme__toggle::after { transform: rotate(180deg); }
/* flattened: the open state is already signalled by the caret and the body. */
.score-readme[open] .score-readme__toggle { border-bottom: 0; }
.score-readme__toggle:hover,
.score-readme__toggle:focus-visible {
  background: var(--paper-3);
  color: var(--ink);
}
.score-readme__toggle:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}
.score-readme__body {
  /* flattened: no rule under a summary that is already visually distinct, and
     no second surface colour inside the card's own. Horizontal padding MATCHES
     the toggle's -- dropping it outdented the open body to the left of its own
     summary, which the flattening never intended. */
  padding: var(--s-2) var(--s-2) 0;
  border-top: 0;
  background: transparent;
}
.score-readme__headline {
  margin: 0 0 var(--s-2);
  font-size: var(--text-sm);
  color: var(--ink);
}
.score-readme__subhead {
  margin: 0 0 4px;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.score-readme__scale {
  margin: var(--s-1) 0 var(--s-2);
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--ink-muted);
}
.score-readme__glossary {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  margin: 0 0 var(--s-2);
}
.score-readme__row {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: var(--s-1);
  align-items: start;
}
.score-readme__row dt {
  font-size: var(--text-xs);
  font-weight: 800;
  color: var(--ink);
  letter-spacing: 0.04em;
  padding-top: 1px;
}
.score-readme__row dd {
  font-size: var(--text-xs);
  color: var(--ink-muted);
  margin: 0;
  line-height: 1.45;
}
.score-readme__row dd a {
  color: var(--ink);
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-underline-offset: 0.15em;
}
.score-readme__row dd a:hover { text-decoration-style: solid; }
.score-readme__footer {
  /* flattened: muted, smaller type already separates this from the body. */
  margin: 0;
  font-size: 0.7rem;
  color: var(--ink-muted);
  border-top: 0;
  padding-top: var(--s-1);
  line-height: 1.4;
}
.score-readme__footer a {
  color: var(--ink-muted);
  text-decoration-line: underline;
  text-decoration-style: dotted;
  text-underline-offset: 0.15em;
}

.card__details {
  /* flattened: the margin and padding already separate this; a rule as well
     made two hairlines inside a single card. The actions row keeps its one. */
  margin-top: var(--s-2);
  border-top: 0;
  padding-top: var(--s-3);
}
.card__more {
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 700;
  color: var(--navy);
  font-size: var(--text-sm);
  list-style: none;
  padding: var(--s-2) 0;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}
.card__more::-webkit-details-marker { display: none; }
.card__more::after { content: " ▾"; }
.card__details[open] .card__more::after { content: " ▴"; }
.card__more:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 4px; padding: var(--s-2); }

.card__details h5 {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  margin: var(--s-3) 0 var(--s-2);
}
.card__details p { margin: 0 0 var(--s-2); font-size: var(--text-sm); color: var(--ink); }

/* History list — recent inspections (worst-offenders) or closure events
   (bad-actors). Renders as a vertical timeline with the date in tabular
   nums on the left and the disposition/violation summary on the right. */
.card__details--supporting {
  margin-top: var(--s-3);
}
.history {
  list-style: none;
  margin: var(--s-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.history__item {
  display: grid;
  grid-template-columns: minmax(7em, auto) 1fr;
  gap: var(--s-3);
  font-size: var(--text-sm);
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--rule);
  background: var(--paper-2);
  border-radius: 0 4px 4px 0;
}
.history__item:nth-child(1) {
  border-left-color: var(--red);
}
.history__item--eor {
  border-left-color: var(--red-deep);
}
.history__link {
  display: contents;
  color: inherit;
  text-decoration: none;
}
.history__link:hover .history__what {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.history__date {
  font-family: var(--font-body);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--ink);
}
.history__what {
  color: var(--ink-2);
}
.history__counts {
  display: block;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  margin-top: 2px;
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
.history__summary {
  color: var(--ink-2);
  font-size: var(--text-sm);
}
.card__trend-signal {
  font-weight: 700;
}
.card__trend-signal--recovering {
  color: var(--green);
}

.violations { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-3); }
.violation {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-3);
  align-items: start;
}
.violation__priority {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px var(--s-2);
  border-radius: 4px;
  align-self: start;
  text-align: center;
  min-width: 3.5em;
  border: 1px solid currentColor;
  text-decoration: none;
  cursor: help;
}
a.violation__priority:hover,
a.violation__priority:focus {
  text-decoration: underline;
  outline-offset: 2px;
}
.violation__priority--hp  { color: var(--red);    background: var(--red-bg); }
.violation__priority--int { color: var(--amber);  background: var(--amber-bg); }
.violation__priority--bas { color: var(--ink-2);  background: var(--paper-3); }
.violation__label { font-weight: 700; font-size: var(--text-sm); color: var(--ink); }
.violation__code {
  font-family: var(--font-body);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--text-xs);
  color: var(--navy);
  text-decoration: none;
  padding: 1px 4px;
  border-radius: 3px;
  background: var(--navy-bg);
  margin-right: var(--s-1);
}
.violation__code:hover { color: var(--paper); background: var(--navy); }
.violation__count {
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  color: var(--ink-muted);
}
.violation__snippet {
  grid-column: 2;
  margin: var(--s-1) 0 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
}
.violation--none { font-style: italic; color: var(--ink-muted); grid-template-columns: 1fr; }

/* ---- Footer --------------------------------------------------- */
.site-footer {
  background: var(--paper-2);
  border-top: 4px solid var(--ink);
  padding: var(--s-5) var(--s-4) var(--s-6);
  margin-top: var(--s-6);
}
.site-footer__inner {
  max-width: var(--measure-grid);
  margin: 0 auto;
  display: grid;
  gap: var(--s-5);
}
.freshness {
  font-size: var(--text-sm);
  color: var(--ink-2);
  margin: 0;
  text-align: center;
}
.freshness strong {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--text-xs);
  display: inline-block;
  margin-right: var(--s-2);
  color: var(--ink-muted);
}
.legal-block { margin: 0; }
.legal-block dt {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  margin-top: var(--s-4);
  margin-bottom: var(--s-2);
}
.legal-block dd { margin: 0; font-size: var(--text-sm); color: var(--ink-2); line-height: 1.55; }
.researcher-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  justify-content: center;
  font-size: var(--text-sm);
}
.researcher-links a {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  padding: 0 var(--s-2);
}
.copyright {
  text-align: center;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  margin: 0;
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
}

/* ---- Data providers showcase ---------------------------------- */
/* Showcase-quality attribution to Foursquare (cuisine + rich data)
   and Google Places (closure verification). Uses each brand's
   official mark + colors. The block is prominent enough that anyone
   from those teams browsing the site sees clean third-party
   attribution; matches developer-attribution guidelines from both
   vendors. */
.data-providers {
  margin: var(--s-5) auto var(--s-4);
  padding: var(--s-4);
  max-width: var(--measure-grid);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 6px;
  text-align: center;
}
.data-providers__heading {
  margin: 0 0 var(--s-3);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-muted);
}
.data-providers__list {
  list-style: none;
  margin: 0 0 var(--s-3);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--s-3);
}
.data-providers__item { margin: 0; }
.data-providers__link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 6px;
  text-decoration: none;
  color: var(--ink);
  font-size: var(--text-sm);
  transition: border-color 120ms ease, transform 120ms ease;
}
.data-providers__link:hover {
  transform: translateY(-1px);
}
.data-providers__link--foursquare:hover { border-color: #F94877; }
.data-providers__link--overture:hover   { border-color: #0B5394; }
.data-providers__link--google:hover     { border-color: #4285F4; }
.data-providers__link--dbpr:hover       { border-color: #0066CC; }
.data-providers__link--sunbiz:hover     { border-color: #C0392B; }
/* DBPR + Sunbiz "wordmark" treatment — text-based logo placeholders
   styled to read as agency-issued without infringing the actual mark.
   DBPR's official logo is lowercase blue "dbpr" with a sun icon in
   the "p"; this approximation uses brand blue + lowercase + bold. */
.data-providers__wordmark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  padding: 2px 8px;
  border-radius: 4px;
  font-weight: 800;
  font-size: var(--text-sm);
  letter-spacing: -0.02em;
  flex-shrink: 0;
}
.data-providers__wordmark--dbpr {
  background: #0066CC;
  color: white;
  text-transform: lowercase;
}
.data-providers__wordmark--sunbiz {
  background: #C0392B;
  color: white;
  text-transform: none;
  font-style: italic;
}
.data-providers__brand {
  font-weight: 700;
}
.data-providers__role {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.data-providers__source {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  font-style: italic;
}
@media (min-width: 1024px) {
  .data-providers {
    max-width: min(720px, 100% - 2 * var(--s-4));
  }
}

/* ---- Share + follow widgets (ShareThis) ----------------------- */
/* AddToAny injects icon buttons into the .a2a_kit host. The follow row
   is a small icon set we render ourselves — three operator-curated
   accounts (Facebook group, IG, Bluesky). Both groups live inside the
   sticky .metro-picker so they stay visible while the reader scrolls. */

.metro-picker__share .a2a_button_facebook,
.metro-picker__share .a2a_button_x,
.metro-picker__share .a2a_button_bluesky,
.metro-picker__share .a2a_button_linkedin,
.metro-picker__share .a2a_button_reddit,
.metro-picker__share .a2a_button_email,
.metro-picker__share .a2a_dd {
  vertical-align: middle;
}

.metro-picker__follow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
}
.follow-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 28px -> 32px (operator 2026-08-21, mobile copy-density audit).
     Note: .metro-picker__social .follow-link (further down this file)
     is a more specific selector that already renders at var(--pill-h)
     = 38px regardless of source order -- this rule is what governs
     .follow-link in any OTHER, less-specific context. */
  width: 32px;
  height: 32px;
  border-radius: 6px;
  color: var(--ink-2);
  text-decoration: none;
  transition: color 120ms ease, background 120ms ease;
}
.follow-link:hover { background: var(--paper-2); }
.follow-link--facebook:hover  { color: #1877F2; }
.follow-link--instagram:hover { color: #E1306C; }
.follow-link--bluesky:hover   { color: #1185FE; }
.follow-link:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.metro-picker__social {
  /* Hidden in the picker bar at all breakpoints — the share+follow
     strip lives in the footer where it has full-width room. Adding
     the jump-nav second row in 2026-04 made the picker too tall on
     mobile when social was also visible (~250px sticky header on a
     phone screen). Footer is the right home; the picker stays lean. */
  display: none;
}
@media (min-width: 1024px) {
  /* Desktop: same — social-in-picker stays hidden. (The old
     grid-template-columns override here is gone; the masthead is flex —
     see "UNIFIED COMMAND BAR flex layout".) */
  .metro-picker__social { display: none; }
}

/* Footer share + follow strip — visible at all breakpoints. On
   narrow viewports the HEADER social block remains primary and this
   footer strip is a duplicate fallback the reader scrolls past. On
   wide viewports the header social is hidden (above) and this strip
   is the only share surface. AddToAny is fine with two .a2a_kit
   instances; the script binds both. */
.site-footer__share {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
}
.site-footer__share-row {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}
.site-footer__share-label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}
.metro-picker__social-group {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}
/* Inline label sits directly in front of each ShareThis button group:
   "share" [icons] "follow" [icons]. Visible at every breakpoint. */
.metro-picker__social-label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: lowercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin-right: var(--s-1);
  white-space: nowrap;
}
.metro-picker__social-label + .a2a_kit,
.metro-picker__social-label + .metro-picker__follow {
  margin-right: var(--s-3);
}

/* ---- Print ---------------------------------------------------- */
@media print {
  :root { --paper: #fff; --ink: #000; }
  .skip-link, .metro-picker, .more-cards__summary, .card__more,
  .researcher-links, .metro-picker__social { display: none !important; }
  body { background: #fff; color: #000; }
  a { text-decoration: underline; color: #000; }
  /* Force every card to render for print. Browsers are supposed to treat
     printing as making skipped content relevant, so `content-visibility: auto`
     should already resolve to visible here -- but a printed page that silently
     omits cards is an expensive way to discover an engine that gets this wrong,
     and the override costs one declaration. */
  .card { break-inside: avoid; content-visibility: visible; }
  /* Paging furniture is meaningless on paper. */
  .more-cards__row, .more-cards__sentinel, .more-cards__status { display: none !important; }
  .metro-panel { padding: 0; }
}

/* ---- High-contrast preference -------------------------------- */
@media (prefers-contrast: more) {
  :root {
    --rule: #5A544A;
    --rule-strong: #1A1A1A;
    --ink-muted: #38332C;
  }
  .metro-chip { border-width: 3px; }
  .stat-tile { border-width: 2px; }
}

/* ---- Card v1.0.13 additions ---------------------------------- */
.card__address {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
.card__chain {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  font-style: italic;
}
.card__chain strong { color: var(--ink); font-style: normal; }

/* Cuisine kicker — single emoji + short label sourced from
   riskyeats.render.cuisine_classify. Sits between the business name
   and the location, italicized in the body font so it reads as
   editorial annotation rather than a UI tag. The emoji carries the
   visual weight; the label is muted text. */
.card__cuisine {
  margin: 2px 0 4px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: 1.2;
  letter-spacing: 0.005em;
}
/* The cuisine emoji is kept -- 102 distinct glyphs carry real scanning value
   and replacing them means authoring 102 SVGs. But an emoji's advance width
   varies by platform, so left inline it pushes the cuisine label a different
   distance on every machine. Give it a fixed slot instead: the label then
   starts in the same place regardless of which glyph, or none, precedes it. */
.card__cuisine-emoji {
  display: inline-block;
  width: 1.25em;
  text-align: center;
  font-style: normal;
}
/* Generic restaurant tags get muted further so they don't scream
   "we don't know what this is" — just a quiet 🍴. */
.card__cuisine--generic { opacity: 0.7; }

/* Brand chain line — from Overture's brand.wikidata. Sits below the
   inspection metric, sibling-class to .card__chain (existing
   multi-location operator detection) but with its own visual key so
   we can tell which signal fired which line in code review. */
.card__brand {
  margin: 0 0 4px;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  font-style: italic;
}
.card__brand-name { color: var(--ink); font-style: italic; font-weight: 600; }
.card__brand-link {
  color: var(--ink);
  font-style: italic;
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px dotted var(--ink-muted);
}
.card__brand-link:hover,
.card__brand-link:focus-visible {
  color: var(--navy);
  border-bottom-style: solid;
  border-bottom-color: var(--navy);
}
/* Franchisee link — operator entity, links to Sunbiz. Rendered in
   the same chain badge so a reader can see "who runs this place"
   one click away from the corporate record. */
.card__franchisee-link,
.card__franchisee-name {
  color: var(--ink);
  font-style: italic;
  font-weight: 600;
  text-decoration: none;
}
.card__franchisee-link {
  border-bottom: 1px dotted var(--ink-muted);
}
.card__franchisee-link:hover,
.card__franchisee-link:focus-visible {
  color: var(--navy);
  border-bottom-style: solid;
  border-bottom-color: var(--navy);
}
/* Per-kind chain badge tints — subtle, only differ in the
   indicator stripe so a reader scanning the column can tell
   national-corp from franchisee-of-national from regional-only.
   National = navy (corporate); franchise = amber (mixed); regional
   = green (independent operator scaling up). */
.card__brand--national   { border-left: 2px solid var(--navy); padding-left: 6px; }
.card__brand--franchise  { border-left: 2px solid var(--amber, #B85C00); padding-left: 6px; }
.card__brand--regional   { border-left: 2px solid var(--green, #1B873F); padding-left: 6px; }

/* Verify-details collapsible — phone / website / socials + provenance
   footer. Tinted neutral so it visually reads as ancillary verification
   surface, not a primary card data row. Mirrors the fb / news details
   pattern (same summary cursor, expand chevron treatment). */
/* 2026-08-06: no longer a <summary> -- contact & provenance render always
   (operator). Keep the same ancillary weight so promoting it from behind a
   click did not also promote it visually over the card's primary rows. */
.card__details--verify summary,
.card__verify-label {
  color: var(--ink-2);
  font-weight: 600;
}
.card__verify-label { margin: var(--s-2) 0 0; font-size: var(--text-sm); }
.card__verify-body {
  padding: 8px 10px;
  background: var(--paper-2);
  border-radius: 4px;
  margin-top: 4px;
}
.card__verify-row {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 10px;
  align-items: center;
}
.card__verify-link {
  color: var(--navy);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
  font-size: var(--text-sm);
}
.card__verify-link:hover,
.card__verify-link:focus-visible { border-bottom-style: solid; }
.card__verify-meta {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--ink-muted);
  font-style: italic;
}
.card__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin: 0;
}
.card__link {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 2px var(--s-2);
  font-size: var(--text-xs);
  font-weight: 700;
  border: 1px solid var(--navy);
  background: var(--navy-bg);
  color: var(--navy);
  border-radius: 4px;
  text-decoration: none;
}
.card__link:hover { background: var(--navy); color: var(--paper); }
.card__pest {
  display: inline-block;
  margin-left: var(--s-2);
  padding: 1px 6px;
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: #58348B;
  color: var(--paper);
  border-radius: 3px;
}
.card__sunbiz {
  font-size: var(--text-xs);
  color: var(--red);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* FSQ-OS-Places "marked closed on YYYY-MM-DD" tag rendered inline on
   permanent-closures cards. Editorial value: gives reader the date FSQ
   noticed the closure, often weeks-to-months ahead of DBPR's admin
   action. Pink to match the FSQ source-pill color (#F94877 family). */
.card__fsq-closed {
  font-size: var(--text-xs);
  color: #B82F58;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* Tighten internal-card vertical rhythm globally — cards had too much
   whitespace between blocks per operator feedback. */
.card__stats { margin: 0; gap: var(--s-1); }
.card__stat dt { font-size: var(--text-xs); margin: 0; }
.card__stat dd { margin: 0; }
.card__counts { margin: 0; font-size: var(--text-xs); }
.card__disposition { margin: 0; font-size: var(--text-sm); }

/* ---- Privacy-policy button ---------------------------------- */
/* Operator wants the footer privacy disclosure to read as a button,
   not a hyperlink-styled <summary>. Style the disclosure summary
   with our standard button chrome (navy outline + bg-tint). */
.share-block__privacy summary {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--navy);
  background: var(--navy-bg);
  border: 1px solid var(--navy);
  border-radius: 4px;
  list-style: none;
}
.share-block__privacy summary::-webkit-details-marker { display: none; }
.share-block__privacy summary::after { content: " ▾"; margin-left: var(--s-1); }
.share-block__privacy[open] summary { background: var(--navy); color: var(--paper); }
.share-block__privacy[open] summary::after { content: " ▴"; }
.share-block__privacy[open] > div { margin-top: var(--s-3); }
.share-block__privacy-body {
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--ink);
  max-width: 65ch;
}
.share-block__privacy-body p { margin: 0 0 var(--s-2); }
.share-block__privacy-body p:last-child { margin-bottom: 0; }
.share-block__privacy-body a { color: var(--navy); text-decoration: underline; }

/* ---- Card kind color coding (left-stripe + small badge) ----- */
/* Each dimension gets a colored left-stripe so a reader can scan a
   long stack and see at-a-glance what kind of card they're looking at. */
/* Card stripe colors per 5-bucket UX scheme. */
.card--under-emergency-order { border-left: 6px solid var(--dim-red-alert); }
.card--recent-failures      { border-left: 6px solid var(--dim-near-miss); }
.card--worst-offenders      { border-left: 6px solid var(--dim-worst-offenders); }
.card--bad-actors           { border-left: 6px solid var(--dim-worst-offenders); }
.card--most-improved        { border-left: 6px solid var(--dim-most-improved); }
.card--clean-plates         { border-left: 6px solid var(--dim-clean-plates); }
.card--permanent-closures   { border-left: 6px solid var(--dim-closures); }
.card--lost-licenses        { border-left: 6px solid var(--dim-owner-changed); }
.card--openings             { border-left: 6px solid var(--dim-openings); }
.card--new-licenses         { border-left: 6px solid var(--dim-openings); }

.card__kind-badge {
  display: inline-block;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: var(--badge-radius-tag);
  align-self: flex-start;
}
/* Kind-badge fills follow the same 5-bucket scheme. */
.card--under-emergency-order .card__kind-badge { background: #dc2626; color: var(--paper); }
.card--recent-failures      .card__kind-badge { background: #F97316; color: var(--paper); }
.card--worst-offenders      .card__kind-badge { background: #8B1818; color: var(--paper); }
.card--bad-actors           .card__kind-badge { background: #8B1818; color: var(--paper); }
.card--most-improved        .card__kind-badge { background: #16a34a; color: var(--paper); }
.card--clean-plates         .card__kind-badge { background: #16a34a; color: var(--paper); }
.card--permanent-closures   .card__kind-badge { background: #6B5B4E; color: var(--paper); }
.card--lost-licenses        .card__kind-badge { background: #1A3D6D; color: var(--paper); }
.card--openings             .card__kind-badge { background: #06b6d4; color: var(--paper); }
.card--new-licenses         .card__kind-badge { background: #06b6d4; color: var(--paper); }

/* ---- Metro-picker freshness slug ---------------------------- */
/* Renders right of the metro dropdown — small data-currency line.
   Hidden on narrow viewports (the bar can't fit it). */
.metro-picker__freshness {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  display: none;
  align-items: center;
  gap: var(--s-1);
  white-space: nowrap;
}
@media (min-width: 768px) {
  .metro-picker__freshness { display: inline-flex; }
  /* Word-wrap per device (operator 2026-08-11): on desktop the column is
     the measure — prose fills it instead of stopping at 65ch. */
  :root { --measure-prose: 100%; }
}
.metro-picker__freshness-label {
  text-transform: lowercase;
  letter-spacing: 0.02em;
}
.metro-picker__freshness-date {
  font-weight: 700;
  color: var(--ink);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
.metro-picker__freshness-edition { color: var(--ink-muted); }

/* ---- ShareThis: suppress widget-internal labels ----------- */
/* The platform-api injects its own "Follow us:" / "Share" copy.
   Our inline <span class="metro-picker__social-label"> already does
   that. Hide every ShareThis-internal label class so we don't end
   up with duplicated copy. */
.sharethis-inline-share-buttons .st-label,
.sharethis-inline-share-buttons .st-share-label,
.sharethis-inline-follow-buttons .st-label,
.sharethis-inline-follow-buttons .st-follow-label,
.st-follow-label,
.st-share-counts {
  display: none !important;
}

/* ---- Dimension accordion --------------------------------- */
/* Wrapper that holds the always-visible narrative kicker + the
   collapsed <details> for one dimension. Stack vertically. */
.dimension-block {
  display: flex;
  flex-direction: column;
  gap: 0;
  border-top: 1px solid var(--rule);
  /* Sticky header has 2 rows on desktop (~5rem) + jump-nav (~3rem)
     + toolbar (~3rem) = ~11rem. On mobile the masthead column-stacks
     6 controls (~16rem), so the upper clamp goes to 18rem to clear
     all sticky chrome. */
  scroll-margin-top: clamp(11rem, 28vh, 22rem);
}
.dimension-block:first-child { border-top: 0; }

/* Search filter sets data-search-empty on dim-blocks (and the
   featured-closures section) when zero of their cards match the
   current query. Hidden during search-mode; cleared on filter clear.
   Sections WITH matches keep their summary heading visible so the
   reader can see which dimension each match belongs to. */
.dimension-block[data-search-empty="true"],
.featured-closures[data-search-empty="true"] {
  display: none;
}
/* When the search-mode is on (any non-empty filter active), tighten
   the dim chrome: hide the long-form narrative + explainer prose so
   the matching cards are the dominant content. The dim's summary
   heading stays visible — that's the "what section am I in" anchor
   the operator wants preserved. */
.metro-panel[data-search-mode="on"] .dimension__narrative,
.metro-panel[data-search-mode="on"] .dimension__intro,
.metro-panel[data-search-mode="on"] .dimension__head .dimension__count,
.metro-panel[data-search-mode="on"] .featured-closures__head .featured-closures__count {
  display: none;
}
/* Tighten heading padding while in search mode so the section labels
   read as compact rules between match groups, not as full panels. */
.metro-panel[data-search-mode="on"] .dimension__head,
.metro-panel[data-search-mode="on"] .featured-closures__head {
  padding-top: var(--s-2);
  padding-bottom: var(--s-2);
}
/* The persona's per-dim distributed narrative — always visible above
   the collapsed dimension <details>. Reads first; the summary headline
   under it is the affordance to drill into the cards.
   Two-column layout: icon column (left) + prose+blog-link column. */
.dimension__narrative {
  margin: 0;
  padding: var(--s-3) var(--s-3) var(--s-2);
  background: var(--paper);
  border-left: 4px solid var(--rule);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-3);
  align-items: start;
}
.dimension__narrative-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--paper-2);
  color: var(--ink);
  flex-shrink: 0;
  border: 2px solid currentColor;
}
.dimension__narrative-icon svg {
  display: block;
  width: 24px;
  height: 24px;
}
/* Per-dim icon color tracks the narrative's left-border color. */
/* Operator 2026-05-04: narrative-icon colors must match the canonical
   per-dim palette (config/dimensions.json). Same hex on the pill, the
   section border, the dim icon, AND this narrative-prose ring. */
.dimension-block[data-dim="under-emergency-order"] .dimension__narrative-icon { color: #dc2626; }
.dimension-block[data-dim="recent-failures"]       .dimension__narrative-icon { color: #F97316; }
.dimension-block[data-dim="worst-offenders"]       .dimension__narrative-icon { color: #8B1818; }
.dimension-block[data-dim="bad-actors"]            .dimension__narrative-icon { color: #8B1818; }
.dimension-block[data-dim="worsts"]                .dimension__narrative-icon { color: #ff5722; }
.dimension-block[data-dim="most-improved"]         .dimension__narrative-icon { color: #16a34a; }
.dimension-block[data-dim="clean-plates"]          .dimension__narrative-icon { color: #16a34a; }
.dimension-block[data-dim="permanent-closures"]    .dimension__narrative-icon { color: #6B5B4E; }
.dimension-block[data-dim="closures"]              .dimension__narrative-icon { color: #6B5B4E; }
.dimension-block[data-dim="ghost-licenses"]        .dimension__narrative-icon { color: #64748b; }
.dimension-block[data-dim="lost-licenses"]         .dimension__narrative-icon { color: #1A3D6D; }
.dimension-block[data-dim="openings"]              .dimension__narrative-icon { color: #06b6d4; }
.dimension-block[data-dim="new-licenses"]          .dimension__narrative-icon { color: #06b6d4; }
.dimension-block[data-dim="chain-activity"]        .dimension__narrative-icon { color: #9333ea; }
/* Featured Closure Signals re-uses the same icon container so the
   page reads consistently across the always-expanded panel + the
   collapsed dim panels. */
.featured-closures .dimension__narrative-icon { color: var(--ink); }
.dimension__narrative-body {
  min-width: 0;
}
.dimension__narrative-prose {
  margin: 0 0 var(--s-1);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.65;
  color: var(--ink);
  /* Fills its grid column per device (was a fixed 75ch that stranded a
     third of every desktop commentary block as dead space — operator
     2026-08-11: "needs to word wrap per device"). */
  max-width: var(--measure-prose);
}
.dimension__narrative-blog-link {
  display: inline-block;
  margin-top: var(--s-1);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--red);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.dimension__narrative-blog-link:hover,
.dimension__narrative-blog-link:focus-visible {
  color: var(--red-deep);
  text-decoration-thickness: 2px;
}
/* Per-dim left-border colors echo the section group (health/license)
   so the narrative reads as part of the same color band as the data
   panel below it. */
.dimension-block[data-dim="under-emergency-order"] .dimension__narrative { border-left-color: #dc2626; }
.dimension-block[data-dim="recent-failures"]       .dimension__narrative { border-left-color: #F97316; }
.dimension-block[data-dim="worst-offenders"]       .dimension__narrative,
.dimension-block[data-dim="bad-actors"]            .dimension__narrative { border-left-color: #8B1818; }
.dimension-block[data-dim="worsts"]                .dimension__narrative { border-left-color: #ff5722; }
.dimension-block[data-dim="most-improved"]         .dimension__narrative,
.dimension-block[data-dim="clean-plates"]          .dimension__narrative { border-left-color: #16a34a; }
.dimension-block[data-dim="permanent-closures"]    .dimension__narrative,
.dimension-block[data-dim="closures"]              .dimension__narrative { border-left-color: #6B5B4E; }
.dimension-block[data-dim="ghost-licenses"]        .dimension__narrative { border-left-color: #64748b; }
.dimension-block[data-dim="lost-licenses"]         .dimension__narrative { border-left-color: #1A3D6D; }
.dimension-block[data-dim="openings"]              .dimension__narrative,
.dimension-block[data-dim="new-licenses"]          .dimension__narrative { border-left-color: #06b6d4; }
.dimension-block[data-dim="chain-activity"]        .dimension__narrative { border-left-color: #9333ea; }

/* Each .dimension is a <details> that defaults to closed (except
   red alert + permanent closures). Summary row shows the section
   name + record count, click to expand. */
.dimension {
  border-block: 1px solid var(--rule);
  margin: 0;
  padding: 0;
  /* Account for the sticky masthead+jump-nav strip so a jump-link
     click lands the section heading BELOW the sticky header, not
     hidden under it. Same offset as .card (6rem) — keeps the visual
     anchor consistent across jump types. */
  scroll-margin-top: 6rem;
}
/* Featured Closure Signals panel uses .dimension class so it inherits
   the scroll-margin above. Belt-and-suspenders: re-apply on the
   featured-closures alias in case .featured-closures CSS specificity
   ever overrides .dimension. */
.featured-closures { scroll-margin-top: 6rem; }
.dimension + .dimension { border-top: 0; }
.dimension > summary.dimension__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  cursor: pointer;
  padding: var(--s-3) var(--s-3);
  margin: 0;
  list-style: none;
  background: var(--paper);
  font-family: var(--font-display);
  font-weight: 700;
  min-height: var(--tap);
  transition: background 120ms ease;
}
.dimension > summary.dimension__head:hover { background: var(--paper-2); }
.dimension > summary.dimension__head::-webkit-details-marker { display: none; }
.dimension > summary.dimension__head::after {
  content: "▾";
  color: var(--ink-muted);
  font-family: var(--font-body);
  font-size: var(--text-md);
  transition: transform 140ms ease;
}
.dimension[open] > summary.dimension__head::after { transform: rotate(180deg); }
.dimension__heading {
  margin: 0;
  font-size: var(--text-md);
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  flex: 1;
}
.dimension__icon {
  display: inline-block;
  vertical-align: -4px;
  width: 22px;
  height: 22px;
  margin-right: var(--s-2);
  /* Inherit color from the dimension's accent set on .dimension--<slug>. */
  color: currentColor;
}
.dimension__heading-text {
  /* Inline span — keeps prior heading wrap/balance intact. */
}
/* Per-dim icon color — matches the pill, dim bar, and blog kicker so
   every surface reads from the same hex per dim. Operator 2026-05-04. */
.dimension--under-emergency-order .dimension__icon { color: #dc2626; }
.dimension--bad-actors .dimension__icon,
.dimension--worst-offenders .dimension__icon { color: #8B1818; }
.dimension--worsts .dimension__icon { color: #ff5722; }
.dimension--permanent-closures .dimension__icon,
.dimension--closures .dimension__icon { color: #6B5B4E; }
.dimension--recent-failures .dimension__icon { color: #F97316; }
.dimension--most-improved .dimension__icon,
.dimension--clean-plates .dimension__icon { color: #16a34a; }
.dimension--openings .dimension__icon,
.dimension--new-licenses .dimension__icon { color: #06b6d4; }
.dimension--ghost-licenses .dimension__icon { color: #64748b; }
.dimension--lost-licenses .dimension__icon { color: #1A3D6D; }
.dimension--chain-activity .dimension__icon { color: #9333ea; }
.dimension__count {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  white-space: nowrap;
}
.dimension > .card-stack,
.dimension > .more-cards__btn,
.dimension > .empty {
  margin: var(--s-3);
}

/* Color the accordion summary stripe per-dimension to match the
   card-kind color coding so the stripe carries through even when
   the section is collapsed. */
.dimension--under-emergency-order > summary.dimension__head { border-left: 6px solid var(--dim-red-alert); padding-left: var(--s-3); }
.dimension--permanent-closures   > summary.dimension__head { border-left: 6px solid var(--dim-closures); padding-left: var(--s-3); }
.dimension--closures             > summary.dimension__head { border-left: 6px solid var(--dim-closures); padding-left: var(--s-3); }
.dimension--recent-failures      > summary.dimension__head { border-left: 6px solid var(--dim-near-miss); padding-left: var(--s-3); }
.dimension--worst-offenders      > summary.dimension__head { border-left: 6px solid var(--dim-worst-offenders); padding-left: var(--s-3); }
.dimension--bad-actors           > summary.dimension__head { border-left: 6px solid var(--dim-worst-offenders); padding-left: var(--s-3); }
.dimension--worsts               > summary.dimension__head { border-left: 6px solid var(--dim-worst-offenders); padding-left: var(--s-3); }
.dimension--most-improved        > summary.dimension__head { border-left: 6px solid var(--dim-most-improved); padding-left: var(--s-3); }
.dimension--clean-plates         > summary.dimension__head { border-left: 6px solid var(--dim-most-improved); padding-left: var(--s-3); }
.dimension--ghost-licenses       > summary.dimension__head { border-left: 6px solid var(--dim-license-paper); padding-left: var(--s-3); }
.dimension--lost-licenses        > summary.dimension__head { border-left: 6px solid var(--dim-owner-changed); padding-left: var(--s-3); }
.dimension--openings             > summary.dimension__head { border-left: 6px solid var(--dim-openings); padding-left: var(--s-3); }
.dimension--new-licenses         > summary.dimension__head { border-left: 6px solid var(--dim-openings); padding-left: var(--s-3); }
.dimension--chain-activity       > summary.dimension__head { border-left: 6px solid var(--dim-chain-activity); padding-left: var(--s-3); }

/* ---- Persistent dimension tabs ----------------------------------
   The masthead may slide away during reading, but its five primary group
   controls must not. The tab strip is therefore a sibling sticky layer: it
   sits below the masthead while that is visible, then floats at viewport top
   whenever JS applies .metro-picker--hidden. --metro-picker-height is kept
   current by the masthead ResizeObserver in index.html.j2. */
.jump-nav-container {
  margin: 0;
  padding: var(--s-2) var(--s-4);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-2);
  position: sticky;
  top: var(--metro-picker-height, 0px);
  z-index: 49;
  transition: top 220ms ease, box-shadow 220ms ease;
}
.jump-nav-container--masthead-hidden {
  top: 0;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.12);
}
/* Mobile: right-edge fade so readers see the strip is horizontally
   scrollable. Hidden once the strip is scrolled to its end via the
   data-scroll-end attribute that the JS scrollspy toggles. */
@media (max-width: 1023px) {
  .jump-nav-container::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 28px;
    pointer-events: none;
    background: linear-gradient(to right, transparent, var(--paper-2));
    transition: opacity 140ms ease;
  }
  .jump-nav-container[data-scroll-end="true"]::after { opacity: 0; }
}
.jump-nav {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  gap: var(--s-1);
  margin: 0 auto;
  max-width: var(--measure-grid);
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--s-2);
}
@media (min-width: 1024px) {
  .jump-nav {
    flex-wrap: wrap;
    overflow-x: visible;
    max-width: min(1100px, 100% - 2 * var(--s-4));
    scroll-snap-type: none;
  }
}
/* (Compact-mode jump-nav rule removed 2026-05-02 — is-compact class
   was never set after the masthead/lede observer surfaces went away.) */
.jump-nav__link {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-1);
  /* This block's padding/font-size are overridden on desktop by the
     later ".jump-nav__link { height: var(--pill-h); padding: 0
     var(--pill-pad-x); font-size: var(--text-sm); }" rule further down
     (same selector, later in source order wins) and on mobile by the
     max-width:1023px override below -- so this padding is dead weight
     past ~1023px and shouldn't be read as controlling the visible size.
     Left at its original 4px so nothing here silently changes; the
     actual pill-size fix lives in the --pill-h/--pill-pad-x tokens. */
  padding: 4px var(--s-2);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-decoration: none;
  color: var(--navy);
  background: var(--navy-bg);
  border: 1px solid var(--navy);
  border-radius: 4px;
  white-space: nowrap;
  scroll-snap-align: start;
}
.jump-nav__link:hover { background: var(--navy); color: var(--paper); }
/* Mobile: WCAG-compliant 36px tap target (was ~22px). Center-align the
   label vertically once we have real height. */
@media (max-width: 1023px) {
  .jump-nav__link {
    padding: 8px var(--s-2);
    min-height: 36px;
    align-items: center;
  }
}
/* Active pill — set by the scrollspy when its dimension is in view.
   Inverts the pill colors so the reader can see at-a-glance which
   section they're reading. Stays subordinate to :hover so power-users
   browsing the nav still see hover feedback. */
.jump-nav__link[aria-current="location"] {
  background: var(--navy);
  color: var(--paper);
}
.jump-nav__link[data-group="health"][aria-current="location"] {
  background: var(--red-deep);
  color: var(--paper);
  border-color: var(--red-deep);
}
.jump-nav__link[data-group="license"][aria-current="location"] {
  background: var(--navy);
  color: var(--paper);
  border-color: var(--navy);
}
.jump-nav__count {
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  opacity: 0.8;
}
/* Operator 2026-05-04: replaced coarse `data-group` palette with the
   canonical per-`data-dim` palette below (line ~2680+ — codered/
   badactors/defunct/etc.). Keeping fallback rules here for
   anchors that don't have `data-dim` (e.g. the legacy distress chip-
   row's `data-group="license"` pills above the briefing). Subtle
   default — the per-dim selectors take over wherever data-dim is set.
   Don't add new colors here; add them at the per-dim block. */
.jump-nav__link[data-group="health"]:not([data-dim]),
.jump-nav__link[data-group="license"]:not([data-dim]) {
  color: var(--ink);
  background: var(--paper);
  border-color: var(--rule);
}
.jump-nav__link[data-group="health"]:not([data-dim]):hover,
.jump-nav__link[data-group="license"]:not([data-dim]):hover {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
/* Operator 2026-05-04: FRI = Florida Restaurant Index analytics —
   purple `#7c3aed` (violet-600). Distinct from chain-activity's
   #9333ea purple-600 by being slightly more violet, less magenta. */
.jump-nav__link[data-group="fri"],
.jump-nav__link--fri {
  color: var(--paper);
  background: #7c3aed;
  border-color: #7c3aed;
  font-weight: 800;
  box-shadow: 0 0 0 1px rgba(124, 58, 237, 0.25);
}
.jump-nav__link[data-group="fri"]:hover,
.jump-nav__link--fri:hover {
  background: #5b21b6;
  color: var(--paper);
  border-color: #5b21b6;
}
.jump-nav__link--fri .jump-nav__count {
  font-weight: 800;
  opacity: 1;
}

/* ─────────────────────────────────────────────────────────────────
 * Operator 2026-05-04 canonical palette — config/dimensions.json.
 * Single source of truth; every pill, kicker, section border, and
 * dim-icon uses ONE of these hex values per dim slug. Don't pick
 * adjacent shades; if a hover variant is needed, darken via filter
 * not a different color.
 *
 *   codered     #dc2626   under-emergency-order      (active emergency)
 *   badactors   #8B1818   bad-actors / worst-offenders
 *                         (chronic offenders — repeat violations)
 *   worsts      #ff5722   worsts                       (cross-flag outlier)
 *   defunct     #6B5B4E   closures / permanent-closures (closed)
 *   conditiongreen #16a34a most-improved / clean-plates (positive)
 *   newopenings #06b6d4   openings / new-licenses     (issuance)
 *   hotspots    #9333ea   chain-activity              (chain rollup)
 *   slate       #64748b   ghost-licenses              (admin grey-zone)
 *   navy        #1A3D6D   lost-licenses               (administrative)
 *   nearmiss    #F97316   recent-failures             (cited but open)
 * ─────────────────────────────────────────────────────────────────*/

/* CODE RED #dc2626 — active enforcement */
.jump-nav__link[data-dim="under-emergency-order"] {
  color: var(--paper);
  background: var(--dim-red-alert);
  border-color: var(--dim-red-alert);
}
/* BAD ACTORS #8B1818 — chronic / repeat offenders */
.jump-nav__link[data-dim="bad-actors"],
.jump-nav__link[data-dim="worst-offenders"] {
  color: var(--paper);
  background: var(--dim-worst-offenders);
  border-color: var(--dim-worst-offenders);
}

/* WORSTS #ff5722 — sunburst orange (cross-flag, multi-dim concentration).
   Operator 2026-05-04: distinct from bad-actors red so the cross-flag
   tier reads at a glance as the "extreme" outlier. */
.jump-nav__link[data-dim="worsts"],
.jump-nav__link[data-group="worsts"] {
  color: var(--paper);
  background: var(--dim-worst-offenders);
  border-color: var(--dim-worst-offenders);
}

/* DEFUNCT #6B5B4E — closed / permanent */
.jump-nav__link[data-dim="permanent-closures"],
.jump-nav__link[data-dim="closures"] {
  color: var(--paper);
  background: var(--dim-closures);
  border-color: var(--dim-closures);
}

/* NEAR MISS #F97316 — cited but still operating */
.jump-nav__link[data-dim="recent-failures"] {
  color: var(--paper);
  background: var(--dim-near-miss);
  border-color: var(--dim-near-miss);
}

/* CONDITION GREEN #16a34a — positive */
.jump-nav__link[data-dim="most-improved"] {
  color: var(--paper);
  background: var(--dim-most-improved);
  border-color: var(--dim-most-improved);
}
.jump-nav__link[data-dim="clean-plates"] {
  color: var(--paper);
  background: var(--dim-clean-plates);
  border-color: var(--dim-clean-plates);
}

/* NEW OPENINGS #06b6d4 — issuance */
.jump-nav__link[data-dim="openings"],
.jump-nav__link[data-dim="new-licenses"] {
  color: var(--paper);
  background: var(--dim-openings);
  border-color: var(--dim-openings);
}

/* SLATE #64748b — ghost / admin grey-zone */
.jump-nav__link[data-dim="ghost-licenses"] {
  color: var(--paper);
  background: var(--dim-license-paper);
  border-color: var(--dim-license-paper);
}
.jump-nav__link[data-dim="lost-licenses"] {
  color: var(--paper);
  background: var(--dim-owner-changed);
  border-color: var(--dim-owner-changed);
}

/* HOTSPOTS #9333ea — chain rollup */
.jump-nav__link[data-group="chain"],
.jump-nav__link[data-dim="chain-activity"] {
  color: var(--paper);
  background: var(--dim-chain-activity);
  border-color: var(--dim-chain-activity);
}

/* Operator 2026-05-04 (rev 3) — pill hover. Earlier `filter: brightness(0.82)`
   was clipping the contained text on some browsers (pills appeared to
   "disappear" on hover). Switched to a 2px ink ring via box-shadow +
   slight saturate boost; preserves dim-color, never affects layout, no
   stacking-context side-effects. */
.jump-nav__link[data-dim]:hover,
.jump-nav__link[data-group="worsts"]:hover,
.jump-nav__link[data-group="chain"]:hover,
.jump-nav__link--fri:hover {
  box-shadow: 0 0 0 2px var(--ink);
}
/* Spacer between health and license groups: the rule below targets
   any license-pill immediately preceded by a health-pill, which is
   only true at the group boundary. */
.jump-nav__link[data-group="health"] + .jump-nav__link[data-group="license"] {
  margin-left: var(--s-3);
}

/* ---- ShareThis: aggressive label suppression -------------- */
/* The first pass missed ShareThis's actual class names (their JS
   injects a label without our hide-list classes). Wildcard match
   any class containing "label" / "text" / "header" anywhere inside
   either widget container. The icon buttons use class names like
   `st-btn` / `st-btns` which do NOT match label/text/header, so the
   icons stay visible. */
.sharethis-inline-share-buttons [class*="label" i],
.sharethis-inline-share-buttons [class*="text" i],
.sharethis-inline-share-buttons [class*="header" i],
.sharethis-inline-share-buttons [class*="title" i],
.sharethis-inline-follow-buttons [class*="label" i],
.sharethis-inline-follow-buttons [class*="text" i],
.sharethis-inline-follow-buttons [class*="header" i],
.sharethis-inline-follow-buttons [class*="title" i] {
  display: none !important;
}

/* ---- Briefing mentions: color-coded per dimension ---- */
/* When the briefing names a restaurant, wrap the name in a colored
   underline + bold so the reader can scan and see what kind of
   trouble each named place is in (red = closure / near miss,
   navy = bad actor, amber = lost license, green = clean / new). */
.briefing-mention {
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.15em;
}
.briefing-mention--under-emergency-order { color: #dc2626; text-decoration-color: #dc2626; }
.briefing-mention--permanent-closures   { color: #6B5B4E; text-decoration-color: #6B5B4E; }
.briefing-mention--closures             { color: #6B5B4E; text-decoration-color: #6B5B4E; }
.briefing-mention--recent-failures      { color: #F97316; text-decoration-color: #F97316; }
.briefing-mention--worst-offenders      { color: #8B1818; text-decoration-color: #8B1818; }
.briefing-mention--bad-actors           { color: #8B1818; text-decoration-color: #8B1818; }
.briefing-mention--worsts               { color: #ff5722; text-decoration-color: #ff5722; }
.briefing-mention--most-improved        { color: #16a34a; text-decoration-color: #16a34a; }
.briefing-mention--clean-plates         { color: #16a34a; text-decoration-color: #16a34a; }
.briefing-mention--ghost-licenses       { color: #64748b; text-decoration-color: #64748b; }
.briefing-mention--lost-licenses        { color: #1A3D6D; text-decoration-color: #1A3D6D; }
.briefing-mention--openings             { color: #06b6d4; text-decoration-color: #06b6d4; }
.briefing-mention--new-licenses         { color: #06b6d4; text-decoration-color: #06b6d4; }
.briefing-mention--chain-activity       { color: #9333ea; text-decoration-color: #9333ea; }

/* Source-attribution icons after a mention. Used to mark closures
   confirmed by Google Places (multicolor G) or flagged by Foursquare
   (pink check square). The icon sits inline after the name with a
   small left margin and slight baseline lift for vertical alignment.
   The two extra modifier classes (--google-confirmed and
   --fsq-confirmed) lift the visual weight: thicker underline, bolder
   color treatment, so the reader's eye lands on confirmed cases first.
   Google = strong confirmation tier (external customer-facing
   attestation). FSQ = secondary signal. DBPR and Sunbiz signals are
   preserved on the underlying card data for historical / post-mortem
   reference but don't add prose emphasis. */
.briefing-mention__source-icon {
  display: inline-block;
  vertical-align: -1px;
  margin-left: 3px;
  flex-shrink: 0;
}
.briefing-mention__check {
  display: inline-block;
  margin-right: 3px;
  color: #1B873F;
  font-weight: 800;
}
.briefing-mention--google-confirmed {
  text-decoration-thickness: 3px;
  text-decoration-color: #4285F4;
  background: rgba(66, 133, 244, 0.07);
  padding: 0 3px;
  border-radius: 2px;
}
.briefing-mention--fsq-confirmed {
  text-decoration-thickness: 3px;
  text-decoration-color: #F94877;
}
.briefing-mention--fb-confirmed {
  text-decoration-thickness: 3px;
  text-decoration-color: #1877F2;
  background: rgba(24, 119, 242, 0.06);
  padding: 0 3px;
  border-radius: 2px;
}

/* Sunbiz / corporate operator line — visible on every card so
   readers see the legal-entity owner. Status badge color-codes
   active vs dissolved. */
.card__sunbiz-line {
  margin: 4px 0 6px;
  font-size: 13px;
  color: var(--ink-mute, #555);
}
.card__sunbiz-label {
  font-weight: 600;
  color: var(--ink, #1a1a1a);
}
.card__sunbiz-status {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 3px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin-left: 4px;
  background: #e9f3e9;
  color: #1B873F;
}
.card__sunbiz-status--inactive,
.card__sunbiz-status--dissolved,
.card__sunbiz-status--admin-dissolved-for-annual-report,
.card__sunbiz-status--admin-dissolution-for-annual-report,
.card__sunbiz-status--admin-dissolved {
  background: rgba(220, 38, 38, 0.1);
  color: #b30000;
}

/* Multi-source confirmation badge row. Each source (FB, Google, Sunbiz,
   DBPR, LLM, FSQ) gets its own pill so a reader sees instantly which
   independent sources corroborate the card. */
.card__sources-row {
  margin: 4px 0 6px;
  font-size: 11px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}
.card__source-badge {
  display: inline-block;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-tag);
  font-size: var(--badge-font);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: white;
}
/* Sunbiz pill becomes a link when corp data is present. Keep the pill
   visually identical to its non-link siblings, but indicate interactivity
   on hover/focus and ensure focus is visible for keyboard users. */
.card__source-badge-link {
  display: inline-block;
  text-decoration: none;
}
.card__source-badge-link:hover .card__source-badge,
.card__source-badge-link:focus-visible .card__source-badge {
  filter: brightness(1.12);
}
.card__source-badge-link:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
  border-radius: var(--badge-radius-tag);
}
/* Inline Sunbiz authority link (operator line + body stat rows).
   Renders as a single anchor wrapping name + ↗ icon (single tab stop).
   Underline-on-hover keeps the editorial tone in dense card bodies. */
.sunbiz-link {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dotted currentColor;
}
.sunbiz-link:hover,
.sunbiz-link:focus-visible {
  border-bottom-style: solid;
  color: var(--navy);
}
.sunbiz-link:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
  border-radius: 2px;
}
.sunbiz-link__icon {
  display: inline-block;
  margin-left: 0.2em;
  font-size: 0.85em;
  opacity: 0.7;
  vertical-align: baseline;
}
.card__confidence-label {
  font-size: 11px;
  font-weight: 600;
  color: #555;
  margin-left: 4px;
}

/* Confidence label on FB-announced cards. Single-source = signal-only
   amber/grey; multi-source = corroborated solid badge. */
.card__confidence {
  display: inline-block;
  margin: 4px 0;
  padding: 2px 8px;
  border-radius: 3px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.card__confidence--signal-only {
  background: #fff5e6;
  color: #b85c00;
  border: 1px dashed #b85c00;
}
.card__confidence--corroborated {
  background: rgba(24, 119, 242, 0.1);
  color: #1877F2;
  border: 1px solid #1877F2;
}
.card__sources {
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0;
  text-transform: lowercase;
  margin-left: 4px;
}

/* FB-announced extras block on social-signal cards. */
.card__details--fb summary {
  color: #1877F2;
  font-weight: 600;
}
.card__fb-body {
  padding: 8px 10px;
  background: rgba(24, 119, 242, 0.04);
  border-radius: 4px;
  margin-top: 4px;
}
.card__fb-link {
  color: #1877F2;
  font-weight: 600;
  text-decoration: underline;
}
.card__fb-meta {
  font-size: 12px;
  color: #666;
  margin: 6px 0 0;
}

/* News-source extras block on closure-signal cards. Mirrors fb-extras
   pattern but tinted teal to match the news pill color (#0E7C66). */
.card__details--news summary {
  color: #0E7C66;
  font-weight: 600;
}
.card__news-body {
  padding: 8px 10px;
  background: rgba(14, 124, 102, 0.05);
  border-radius: 4px;
  margin-top: 4px;
}
.card__news-headline {
  font-style: italic;
  color: var(--ink, #1a1a1a);
  margin: 0 0 6px;
}
.card__news-link {
  color: #0E7C66;
  font-weight: 600;
  text-decoration: underline;
}
.card__news-meta {
  font-size: 12px;
  color: #666;
  margin: 6px 0 0;
}
.card__ocr-block {
  margin-top: 6px;
  font-size: 12px;
}
.card__ocr {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 11px;
  background: #fff;
  padding: 6px 8px;
  border: 1px solid #ddd;
  border-radius: 3px;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 180px;
  overflow: auto;
  margin: 4px 0 0;
}

/* ---- Brand block: name + tagline ---------------------- */
/* Small italic tagline beneath the wordmark so a first-time visitor
   knows what the site is without scrolling. Tagline hides under
   600px (the bar can't fit it on phones). */
.metro-picker__brand {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  line-height: 1;
  text-decoration: none;
  color: var(--red);
  white-space: nowrap;
  padding: 8px 16px;
  border: 2px solid var(--red);
  border-radius: 999px;
  background: var(--red-bg, #fdecec);
  transition: background .15s ease;
}
.metro-picker__brand:hover,
.metro-picker__brand:focus-visible {
  background: var(--red);
}
.metro-picker__brand:hover .metro-picker__brand-name,
.metro-picker__brand:focus-visible .metro-picker__brand-name {
  color: var(--paper);
}
.metro-picker__brand-name {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 800;
  font-variation-settings: "opsz" 64, "wdth" 90;
  line-height: 1;
  color: var(--red);
}
.metro-picker__brand-tagline {
  display: none;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-style: italic;
  font-weight: 400;
  color: var(--ink-muted);
  letter-spacing: 0;
  margin-top: 2px;
}
@media (min-width: 600px) {
  .metro-picker__brand-tagline { display: block; }
}


/* ---- Site nav (#111 cross-site pill navigation) ----------------
   Three links (FRI, Methodology, Blog) embedded in the sticky
   metro-picker header. On mobile: pills wrap into a scrollable row;
   each pill is a pill-badge. On desktop the bar has room for all three.
   Without explicit styles these render as plain block links, unusable
   on narrow viewports. */
.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;      /* Firefox */
  padding-bottom: 2px;        /* prevents clipping of bottom border on scroll */
}
.site-nav::-webkit-scrollbar { display: none; }
.site-nav__link {
  display: inline-block;
  padding: 4px 12px;
  border: 1px solid var(--rule);
  border-radius: 20px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap;
  flex-shrink: 0;
}
.site-nav__link:hover {
  border-color: var(--ink-muted);
  color: var(--ink);
}
/* Section pills — each distinct (operator 2026-06-21): Blog·News·Intelligence·Data·Methodology */
.site-nav__link--blog   { color:#6d28d9; background:#f5f3ff; border-color:#ddd6fe; }
.site-nav__link--news   { color:#1f2937; background:#faf7f0; border-color:#e7e0d2; }
.site-nav__link--fri    { color:#b91c1c; background:#fef2f2; border-color:#fecaca; }
.site-nav__link--data   { color:#475569; background:#f1f5f9; border-color:#cbd5e1; }
.site-nav__link--method { color:#0f766e; background:#f0fdfa; border-color:#99f6e4; }
.site-nav__link--blog:hover   { border-color:#6d28d9; color:#6d28d9; }
.site-nav__link--news:hover   { border-color:#1f2937; color:#1f2937; }
.site-nav__link--fri:hover    { border-color:#b91c1c; color:#b91c1c; }
.site-nav__link--data:hover   { border-color:#475569; color:#475569; }
.site-nav__link--method:hover { border-color:#0f766e; color:#0f766e; }
@media (max-width: 599px) {
  .site-nav {
    flex-wrap: nowrap;   /* force single row, allow scroll */
  }
  /* …but the nav folded INTO the command bar must wrap, not scroll —
     overflow scroll inside the bar would clip pills behind the metro/search
     and reintroduce horizontal overflow on a 320px phone (operator
     2026-06-22). Keep the in-bar nav wrapping at every width. */
  .metro-command__nav.site-nav {
    flex-wrap: wrap;
    overflow: visible;
  }
}

/* ---- Featured Closure Watch module ----------------------------- */
/* Promoted out of the dimension accordion list per GRAEAE UX consult
   2026-04-29. Sits directly under the briefing prose, above the jump
   nav. Always expanded; the most journalistically valuable surface
   on the page. Visual treatment is editorial-card (heavy border, red
   accent, contained card-stack) — distinct from the other panel
   accordions so it reads as the lead story not just another section. */
.featured-closures {
  margin: var(--s-5) 0 var(--s-5);
  padding: var(--s-4) var(--s-4) var(--s-3);
  border-left: 6px solid var(--dim-closures);
  background: linear-gradient(90deg, rgba(153, 27, 27, 0.04), transparent 60%);
  border-radius: 6px;
}
.featured-closures__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-bottom: var(--s-2);
  padding-bottom: var(--s-2);
  border-bottom: 2px solid #6B5B4E;
}
.featured-closures__badge {
  font-family: var(--font-display);
  font-size: var(--badge-font);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--paper);
  background: #6B5B4E;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-tag);
}
.featured-closures__heading {
  margin: 0;
  font-size: var(--text-lg);
  font-family: var(--font-display);
  color: var(--ink);
  flex: 1;
}
.featured-closures__count {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.card__stat--temp-closed dd small {
  display: block;
  margin-top: 2px;
  color: var(--ink-muted);
  font-style: italic;
}

/* ---- Closure Score badge ----------------------------------- */
/* Prominent X/4 score on every Closure Signals card. Tier 1-4 get
   progressively heavier color treatment to scan-rank the stack at
   a glance. See section intro for tier semantics. */
.card__stat--closure-score dd {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.closure-score {
  display: inline-flex;
  align-items: baseline;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.4rem;
  line-height: 1;
  padding: var(--s-1) var(--s-2);
  border-radius: 4px;
  font-variant-numeric: tabular-nums;
}
.closure-score__total {
  font-size: 0.7em;
  font-weight: 600;
  opacity: 0.6;
  margin-left: 1px;
}
.closure-score--tier-1 { background: rgba(245, 158, 11, 0.12); color: var(--amber-deep, #92400e); }
.closure-score--tier-2 { background: rgba(220, 38, 38, 0.10); color: var(--red); }
.closure-score--tier-3 { background: rgba(220, 38, 38, 0.18); color: var(--red-deep); }
.closure-score--tier-4 {
  background: var(--red-deep);
  color: var(--paper);
}

/* ---- External-verifier badge row --------------------------- */
/* Shown inside Closure Signals cards when one or more of Google/
   Yelp/Foursquare has weighed in on the place's status. Compact row
   of provider logos, each linking out to the matched listing. */
.card__stat--verdict {
  border-top: 1px dashed var(--rule);
  padding-top: var(--s-2);
  margin-top: var(--s-2);
}
.provider-logos {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-left: var(--s-2);
  vertical-align: middle;
}
.provider-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 24px -> 28px (operator 2026-08-21, mobile copy-density audit).
     Interactive when linked (renders as an <a target="_blank">), so
     it's a real tap target, not purely decorative. */
  width: 28px;
  height: 28px;
  border-radius: 4px;
  text-decoration: none;
  transition: transform 120ms ease, background 120ms ease;
}
.provider-logo:hover { background: var(--paper-2); transform: scale(1.1); }
.provider-logo:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.verdict-reason {
  display: block;
  margin-top: var(--s-1);
  font-style: italic;
  color: var(--ink-muted);
}

/* Promote tier-4 (externally-confirmed) cards visually — heavier left
   stripe + tinted bg so the eye finds them first in the closure-signals
   stack. Falls back to existing card-stripe color for other tiers. */
.card--permanent-closures.card--tier-4 {
  border-left-width: 8px;
  border-left-color: #6B5B4E;
  background: linear-gradient(90deg, rgba(153, 27, 27, 0.04), transparent 60%);
}

/* ---- Report mapping issue (per-card) ---- */
/* Small bottom-of-card link readers can use to flag a suspected
   mismatch (card shows violations for license X but the user knows
   the actual restaurant is a different license). mailto with
   license_id + business_name pre-filled so audit is fast. */
.card__report {
  margin: 0.6rem 0 0 0;
  padding: 0.3rem 0 0 0;
  border-top: 1px dashed var(--paper-3);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  text-align: right;
}
.card__report-link {
  color: var(--ink-muted);
  text-decoration: none;
  border-bottom: 1px dotted var(--paper-3);
  padding-bottom: 1px;
}
.card__report-link:hover,
.card__report-link:focus-visible {
  color: var(--red);
  border-bottom-color: var(--red);
  outline: none;
}

/* ---- Sparkline + trend chip (bad_actors / worst_offenders) ---- */
/* Server-rendered SVG sparkline shows quarterly event density over
   ~11 years; the trend chip alongside is a single-glance verdict on
   whether the restaurant is worsening, stable, or recovering based on
   recent-540d vs prior-540d event ratio. Goal: reader can scan the
   card without reading the full closure-history list, but can expand
   to receipts via the <details> below. */
.card__sparkline {
  margin: 0.5rem 0 0 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.card__sparkline-label {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-2);
  white-space: nowrap;
}
.sparkline {
  display: block;
  flex: 0 0 auto;
}
.trend-chip {
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 600;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.trend-chip--worsening   { background: var(--red-bg);   color: var(--red-deep); }
.trend-chip--worsening::before { content: "↑"; font-weight: 800; }
.trend-chip--stable      { background: #FEF3C7;          color: #8A6300; }
.trend-chip--stable::before    { content: "→"; }
.trend-chip--recovering  { background: #DCFCE7;          color: #14532D; }
.trend-chip--recovering::before { content: "↓"; }
.trend-chip--no_signal   { background: var(--paper-3);   color: var(--ink-muted); }
.trend-chip--no_signal::before { content: "·"; }

/* ---- Closure / inspection history collapse details ---- */
.card__history-details {
  margin: 0.4rem 0 0 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
}
.card__history-details summary {
  cursor: pointer;
  color: var(--navy);
  font-weight: 600;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.card__history-details summary::before {
  content: "▸";
  display: inline-block;
  transition: transform 0.12s ease;
}
.card__history-details[open] summary::before {
  transform: rotate(90deg);
}
.card__history-details ul {
  list-style: none;
  padding: 0.4rem 0 0 1rem;
  margin: 0;
  border-left: 2px solid var(--paper-3);
  margin-left: 0.4rem;
}
.card__history-details li {
  margin: 0.2rem 0;
  color: var(--ink-2);
  display: flex;
  gap: 0.5rem;
}
.card__history-details li time {
  font-weight: 600;
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  flex: 0 0 auto;
}

/* ---- Briefing paragraph color sectioning ------------------- */
/* Each paragraph in the briefing prose carries a left border tinted
   to match the dimension that the paragraph's first restaurant mention
   belongs to. JS adds .briefing__paragraph--<kind> when it can determine
   which dimension the paragraph is about. */
.briefing__paragraph[data-kind] {
  border-left: 4px solid var(--rule);
  padding-left: var(--s-3);
  margin-left: 0;
}
.briefing__paragraph[data-kind="under-emergency-order"] { border-left-color: #dc2626; }
.briefing__paragraph[data-kind="recent-failures"]       { border-left-color: #F97316; }
.briefing__paragraph[data-kind="worst-offenders"],
.briefing__paragraph[data-kind="bad-actors"]            { border-left-color: #8B1818; }
.briefing__paragraph[data-kind="worsts"]                { border-left-color: #ff5722; }
.briefing__paragraph[data-kind="permanent-closures"],
.briefing__paragraph[data-kind="closures"]              { border-left-color: #6B5B4E; }
.briefing__paragraph[data-kind="most-improved"],
.briefing__paragraph[data-kind="clean-plates"]          { border-left-color: #16a34a; }
.briefing__paragraph[data-kind="openings"],
.briefing__paragraph[data-kind="new-licenses"]          { border-left-color: #06b6d4; }
.briefing__paragraph[data-kind="ghost-licenses"]        { border-left-color: #64748b; }
.briefing__paragraph[data-kind="lost-licenses"]         { border-left-color: #1A3D6D; }
.briefing__paragraph[data-kind="chain-activity"]        { border-left-color: #9333ea; }

.signup__submit-loading { display: none; }
.signup__form[data-state="loading"] .signup__submit-label { visibility: hidden; }
.signup__form[data-state="loading"] .signup__submit-loading {
  display: inline;
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.signup__form[data-state="loading"] .signup__submit { pointer-events: none; }
.signup__form[data-state="ok"] .metro-picker__signup-status      { color: var(--green); }
.signup__form[data-state="error"] .metro-picker__signup-status   { color: var(--red); }

/* ----------------------------------------------------------------------
   Per-metro restaurant search (native <datalist> autocomplete).
   Sits between the brand bar and the jump-nav pills, inside the
   sticky header so it follows the reader. JS rebuilds the form +
   datalist on every metro switch from that metro's loaded JSON.
   Aesthetic matches the signup module (light card chrome, red
   submit) so the two compact masthead modules read as a pair.
   ---------------------------------------------------------------------- */
.metro-search-container {
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--rule);
}
.metro-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-1);
  margin: 0 auto;
  max-width: var(--measure-grid);
}
.metro-search__label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}
.metro-search__submit {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.4rem 0.9rem;
  background: var(--red);
  color: var(--paper);
  border: 1px solid var(--red);
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.metro-search__submit:hover,
.metro-search__submit:focus-visible {
  background: var(--red-deep);
  border-color: var(--red-deep);
  outline: none;
}
.metro-search__status {
  flex: 1 0 100%;
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.78rem;
  color: var(--ink-muted);
  min-height: 1em;
}
.metro-search__status:empty { display: none; }
.metro-picker__contrib-link {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--red-deep, var(--red));
  text-decoration: underline;
  text-underline-offset: 0.2em;
  align-self: center;
  white-space: nowrap;
}
.metro-picker__contrib-link:hover { color: var(--ink); }
/* (Removed: .metro-search__hint — operator 2026-05-02: extra text block not needed; placeholder broadened to 'Name, city, or address…' instead.) */

/* (Compact-mode tightening removed 2026-05-02 — was targeting
   .metro-search-container which never existed in the template
   (real class is .metro-picker__search-wrap). Codex MED LOW finding.) */
@media (max-width: 1023px) {
  .metro-search__label-text {
    font-size: 0.72rem;
  }
}

/* Search-hit highlight — short pulse on the landed card so the
   reader's eye finds it even when the section was already partly
   in view. CSS-only; the class is removed after 1800ms by JS. */
.card--search-hit {
  animation: card-search-hit 1.6s ease-out 1;
  scroll-margin-top: 6rem;
}
@keyframes card-search-hit {
  0%   { box-shadow: 0 0 0 0 rgba(185, 28, 28, 0.55); }
  30%  { box-shadow: 0 0 0 6px rgba(185, 28, 28, 0.18); }
  100% { box-shadow: 0 0 0 0 rgba(185, 28, 28, 0); }
}
/* Always give cards scroll-margin so deep-link jumps don't land
   under the sticky header. Independent of search; benefits any
   #card-* link (briefing-mention rewrite, social shares, etc.). */
.card[id^="card-"] { scroll-margin-top: 6rem; }

/* ---- Announced-closure tier (2026-05-01) -------------------- */
/* Cards in the announced-closure tier carry a moderate-tone badge
   ("Closing YYYY-MM-DD") + a small footer line clarifying the venue
   is still open today. Visually warmer than the critical
   confirmed-closed treatment so readers do not conflate "soon" with
   "already happened". Reuses .risk-band--moderate (amber) which
   matches the temp-closed pattern. */
.card__stat--announced-closure dd small {
  display: block;
  margin-top: 2px;
  color: var(--ink-muted);
  font-style: italic;
}
.card__stat--announced-closure dt {
  /* Slightly stronger emphasis than the default card__stat dt so the
     "Announced closing" row reads as the editorial lead. */
  color: var(--ink);
}

/* ====================================================================
   Phase 0 UX consolidation (2026-05-02) — InspectFL-cherry-pick + 55+
   broadsheet UX principles + space-density tightening.

   Goals (operator directives):
   - Stop wasting so much space
   - Present data immediately (no drilling, no preamble)
   - 55+ readability (18px body min, AAA contrast, ≥44px tap targets)
   - Anti-drill-down: dimension panels open by default
   - Steal what works from InspectFL.org: per-card severity stripe, A-F grade
   - Civic-newspaper aesthetic preserved (deep red, not peach)
   ==================================================================== */

/* ---- Hide the AddToAny "+" share-menu trigger -------------------- */
/* The default "+" icon isn't recognizable as a share affordance.
   We ship explicit per-platform buttons (FB, X, Bluesky, LinkedIn,
   Reddit, Email) — the dropdown is redundant. */
.a2a_dd { display: none !important; }

/* Masthead tightening, blog CTA, and signup chrome are consolidated in
   the unified masthead block near the end of the file. */

/* ---- Anti-drill-down: dimension panels open by default ----------
   InspectFL hides everything behind clicks. We don't. Every panel's
   <details> renders open; users see the data on landing, no click
   required. The summary still toggles open/close for the user who
   wants to collapse, but the default state is OPEN. */
.dimension[open] { display: flex; }
.dimension > summary.dimension__head {
  cursor: pointer;
}
/* Ensure all dimension panels actually open on render. The template
   sets `open` on the first dim by default; for the rest, JS in the
   template will add the `open` attribute on first metro load. */

/* ---- Compact dimension panels -----------------------------------
   Reduce vertical waste between panels + within each panel. */
.dimensions { gap: var(--s-4); }
.dimension { gap: var(--s-3); }
.dimension > summary.dimension__head {
  padding: var(--s-2) 0;
}
.dimension__head {
  padding-bottom: var(--s-1);
}
/* Compact-mode tweak retained for vertical rhythm. Font-size now
   inherits from the canonical rule above (base size for 55+ legibility). */


/* ---- Compact stat-band ------------------------------------------
   Was rendering as a fairly tall table. Tighten + reduce padding so
   it occupies less vertical space above the briefing. */
.stat-band {
  padding: var(--badge-pad-y) var(--badge-pad-x);
}
.stat-band__heading {
  font-size: var(--badge-font);
  letter-spacing: 0.1em;
  margin: 0 0 var(--s-1);
}

/* ---- Tighter cards (same data, less padding) -------------------- */
.card {
  padding: var(--s-2) var(--s-3);
  gap: var(--s-1);
}
.card__head { gap: 1px; }
.card__location { font-size: 0.85rem; }
.card__stats { gap: var(--s-3); }
.card__stat dt { font-size: 0.7rem; }
.card__stat dd { font-size: 0.95rem; }
.card__counts, .card__disposition { font-size: 0.85rem; }

/* ---- Default-open <details> behavior for dimension panels --------
   Cleanly visible disclosure caret that doesn't compete with the
   colored severity stripes inside. Smaller than default, ink color. */
.dimension > summary::-webkit-details-marker { display: none; }
.dimension > summary { list-style: none; }
.dimension > summary::after {
  content: "▾";
  font-size: 0.85em;
  color: var(--ink-muted);
  margin-left: var(--s-2);
  display: inline-block;
  transition: transform 120ms ease;
}
.dimension[open] > summary::after { transform: rotate(180deg); }

/* ---- Wider above-the-fold cap on prose / wide-screen reflow ----
   The briefing prose stays 65ch for readability, but the surrounding
   container can fill 1280px on wide screens. Cards inside dimensions
   already use a grid that scales to multiple columns above 1024px. */
/* FLATTENING 2026-08-05: there was NO column rule below 1280px, so a 1279px
   window rendered one card per row with room for three. And repeat(3) always
   builds three tracks, so a dimension holding two cards left a third of the row
   empty -- which is what "only 2 columns" looked like on the alerts dimension.
   auto-fit collapses empty tracks, so a short row fills the width instead. The
   3-column cap above 1280 is kept: a previous 4-col at 1680px+ made cards
   narrow enough that 'All violations' wrapped badly (operator 2026-05-03). */
/* Scope note for the nine dimensions that carry no risk score. Said ONCE per
   section instead of once per card -- the absence is a property of the
   dimension, and repeating it per card turned a true statement into chrome
   (operator, 2026-08-05). Deliberately quiet: it is a caveat, not a finding. */
/* Evidence count carried INSIDE the one closure chip, so the card states the
   verdict and its corroboration in a single object instead of a chip, a score
   pill, a "(N signals firing)" aside and a second badge row that often repeated
   the verdict verbatim (operator, 2026-08-05). */
.risk-band__count {
  font-weight: 600;
  opacity: 0.85;
  white-space: nowrap;
}

/* Per-source closure rows live behind an expand now. They are evidence FOR the
   chip, not four more claims beside it. */
/* #110: panels that were <details> and are now always visible.
   The operator's rule is that only violation detail and "How this score is
   built" may hide behind a tap; contact, provenance, licensees and closure
   history are shown always.

   The label keeps .card__more's weight/size/colour so the card's visual
   rhythm is unchanged, but drops the affordances that would now be lies:
   no pointer cursor, no min-height tap target, and NO ▾ marker -- a
   disclosure triangle on something that never discloses is the worst of
   both, and is what the empty "4 signals firing" expander looked like. */
.card__panel-label {
  font-family: var(--font-body);
  font-weight: 700;
  color: var(--navy);
  font-size: var(--text-sm);
  margin: var(--s-2) 0 var(--s-1);
}
.card__panel--open { margin: var(--s-2) 0 0; }
.card__ocr-block .card__panel-label { margin-top: var(--s-1); }

.card__closure-evidence { margin: var(--s-2) 0 0; }
.card__closure-evidence .closure-badges { margin: var(--s-2) 0; }
.card__closure-evidence .card__detail-table { width: 100%; }

.card-stack__scope-note {
  margin: 0 var(--s-3) var(--s-2);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--ink-muted);
  max-width: 68ch;
}

/* Cards are a reading feed, not a dashboard mosaic. A wide display gives a
   single card more room to keep related facts on one line; it never creates a
   second card column or an empty track. */
.card-stack { grid-template-columns: minmax(0, 1fr); }

/* A dimension has one visible card face at a time. The floating controls stay
   alongside the dimension jump tabs; every card flips together instead of
   spending vertical space on its own set of controls. */
.card-face-nav {
  display: flex;
  flex: 0 0 100%;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  width: 100%;
  margin: 0;
  padding-top: var(--s-1);
  border-top: 1px solid var(--rule);
  border-left: 0;
}
.card-face-nav__label {
  flex: 0 0 auto;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-weight: 700;
}
.card-face-nav__button {
  /* 30px -> 34px, --text-xs -> --text-sm (operator 2026-08-21, mobile
     copy-density audit -- desktop measured close to 30px too, and
     --text-sm matches what the desktop jump-nav pill already uses,
     further down this file, so the two control families read the
     same size). */
  min-height: 34px;
  padding: 4px 8px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
}
/* A card face describes the same kind of information in every dimension. Its
   colour instead comes from the active dimension, moving light → dark across
   Overview, Inspection, and Status. This makes a face change legible without
   pretending an inspection is orange in Alerts or green in Caution. */
.card-face-nav[data-group="news"],
.dimension--group-news { --face-1: #fff1f2; --face-2: #ffe4e6; --face-3: #fecdd3; --face-ink: #9f1239; --band-1: #ffe4e6; --band-2: #fecdd3; --band-3: #fda4af; }
.card-face-nav[data-group="avoid"],
.dimension--group-avoid { --face-1: #fff7ed; --face-2: #ffedd5; --face-3: #fed7aa; --face-ink: #c2410c; --band-1: #ffedd5; --band-2: #fed7aa; --band-3: #fdba74; }
.card-face-nav[data-group="trusted"],
.dimension--group-trusted { --face-1: #f0fdf4; --face-2: #dcfce7; --face-3: #bbf7d0; --face-ink: #166534; --band-1: #dcfce7; --band-2: #bbf7d0; --band-3: #86efac; }
.card-face-nav[data-group="improving"],
.dimension--group-improving { --face-1: #eff6ff; --face-2: #dbeafe; --face-3: #bfdbfe; --face-ink: #1d4ed8; --band-1: #dbeafe; --band-2: #bfdbfe; --band-3: #93c5fd; }
.card-face-nav[data-group="closed"],
.dimension--group-closed { --face-1: #fafafa; --face-2: #f4f4f5; --face-3: #e4e4e7; --face-ink: #3f3f46; --band-1: #f4f4f5; --band-2: #e4e4e7; --band-3: #d4d4d8; }
.card-face-nav[data-group="explore"],
.dimension--group-explore { --face-1: #ecfeff; --face-2: #cffafe; --face-3: #a5f3fc; --face-ink: #0f766e; --band-1: #cffafe; --band-2: #a5f3fc; --band-3: #67e8f9; }
.card-face-nav[data-group] .card-face-nav__button { color: var(--face-ink); border-color: var(--face-ink); }
.card-face-nav[data-group] .card-face-nav__button[data-card-face="overview"] { background: var(--face-1); }
.card-face-nav[data-group] .card-face-nav__button[data-card-face="inspection"] { background: var(--face-2); }
.card-face-nav[data-group] .card-face-nav__button[data-card-face="status"] { background: var(--face-3); }
.card-face-nav[data-group] .card-face-nav__button.is-active { background: var(--face-ink); color: #fff; }
.card-face-nav__button:focus-visible { outline: 3px solid var(--focus-ring-color, #0f172a); outline-offset: 2px; }
/* COLOUR ON THE FRAME, PAPER UNDER THE TEXT (operator 2026-08-11: "the
   background color is too much, but we want the color highlights … white is
   still probably the best color for readability … it should be the border of
   the card, with a black outline as the separator … each card is enclosed in
   the color, but we may want higher contrast versions of the color rather
   than a light color the background was using").

   The face tints used to fill the card BODY — the surface carrying the
   densest text on the site (inspector prose, violation lists, dossier
   lines). Tinting that costs contrast exactly where it is worth most.

   Now the dimension ENCLOSES the card at full strength, a black hairline
   sits inside the colour as the separator, and the reading surface is paper.
   The face (Overview / Inspection / Status) keeps its light→dark progression
   but on the title band only — and at the SATURATED end of each dimension's
   ramp, because a band bordered in a strong hue needs to hold its own
   against it rather than wash out. */
.dimension--group-news .card,
.dimension--group-avoid .card,
.dimension--group-trusted .card,
.dimension--group-improving .card,
.dimension--group-closed .card,
.dimension--group-explore .card {
  background: var(--paper);
  /* The dimension colour, all four sides — the card is enclosed by it. */
  border: 4px solid var(--face-ink);
  /* Black hairline INSIDE the colour: the separator that keeps a saturated
     frame off the content and gives the card a crisp edge in the
     civic-newspaper register the rest of the site uses. */
  box-shadow: inset 0 0 0 1px var(--ink);
}

.dimension--group-news .card > .card__body > .risk-card-header,
.dimension--group-avoid .card > .card__body > .risk-card-header,
.dimension--group-trusted .card > .card__body > .risk-card-header,
.dimension--group-improving .card > .card__body > .risk-card-header,
.dimension--group-closed .card > .card__body > .risk-card-header,
.dimension--group-explore .card > .card__body > .risk-card-header {
  /* Bleed to the inner edge so the band reads as a title bar rather than a
     floating swatch; the body supplies the padding this cancels. */
  margin: calc(-1 * var(--s-2)) calc(-1 * var(--s-3)) 0;
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--ink);
  background: var(--band-1);
}
.dimension--group-news .card[data-card-face="inspection"] > .card__body > .risk-card-header,
.dimension--group-avoid .card[data-card-face="inspection"] > .card__body > .risk-card-header,
.dimension--group-trusted .card[data-card-face="inspection"] > .card__body > .risk-card-header,
.dimension--group-improving .card[data-card-face="inspection"] > .card__body > .risk-card-header,
.dimension--group-closed .card[data-card-face="inspection"] > .card__body > .risk-card-header,
.dimension--group-explore .card[data-card-face="inspection"] > .card__body > .risk-card-header {
  background: var(--band-2);
}
.dimension--group-news .card[data-card-face="status"] > .card__body > .risk-card-header,
.dimension--group-avoid .card[data-card-face="status"] > .card__body > .risk-card-header,
.dimension--group-trusted .card[data-card-face="status"] > .card__body > .risk-card-header,
.dimension--group-improving .card[data-card-face="status"] > .card__body > .risk-card-header,
.dimension--group-closed .card[data-card-face="status"] > .card__body > .risk-card-header,
.dimension--group-explore .card[data-card-face="status"] > .card__body > .risk-card-header {
  background: var(--band-3);
}
/* Title text sits on the band, so it takes the band's ink. */
.dimension--group-news .card > .card__body > .risk-card-header .card__name,
.dimension--group-avoid .card > .card__body > .risk-card-header .card__name,
.dimension--group-trusted .card > .card__body > .risk-card-header .card__name,
.dimension--group-improving .card > .card__body > .risk-card-header .card__name,
.dimension--group-closed .card > .card__body > .risk-card-header .card__name,
.dimension--group-explore .card > .card__body > .risk-card-header .card__name {
  color: var(--face-ink);
}
.card__face {
  margin-top: var(--s-2);
}
.card__face[hidden] { display: none !important; }
.card__face-empty {
  margin: 0;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-style: italic;
}
.card__inspection-notes,
.card__news-comparison {
  margin: 0 0 var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--rule);
  background: var(--paper);
}
.card__inspection-summary {
  margin: 0 0 var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid #b45309;
  background: var(--paper);
}
.card__inspection-summary h4 {
  margin: 0 0 4px;
  color: #92400e;
  font-size: var(--text-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
}
.card__inspection-summary p { margin: 0; line-height: 1.4; }
.card__inspection-summary p + p { margin-top: 4px; }
.card__inspection-counts { font-weight: 700; }
.card__inspection-disposition span { font-weight: 700; }
.card__inspection-trend { color: var(--ink-2); }
.card__inspection-overview {
  margin: 0;
  color: var(--ink-2);
  font-size: var(--text-sm);
  line-height: 1.45;
}
/* Venue-type microlabel in the cuisine slot (kind="venue" classifier hits:
   Church, Hospital, Stadium…) — establishment type, not a cuisine. */
.card__cuisine-venue-micro {
  font-style: normal;
  font-weight: 700;
  font-size: 0.72em;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
/* Muted age qualifier on receipts >= ~3 months old (2026-08-11). */
.card__receipt-age {
  color: var(--ink-muted);
  font-weight: 600;
  font-size: 0.85em;
}
/* Dossier regulatory-context lines (moved from Overview stats, 2026-08-11). */
.card__reg-line {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink-2);
  line-height: 1.5;
}
.card__reg-label {
  font-weight: 700;
  color: var(--ink-1, inherit);
}
/* The closure evidence trail (2026-08-15, restoring _closure_history).
   An ordered list because the ORDER is the argument: three dated facts in
   sequence read as a story, the same three unordered read as a badge set. */
.closure-trail { margin: 0; padding: 0; list-style: none; }
.closure-trail__item {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 3px 0;
  font-size: var(--text-sm);
  line-height: 1.45;
}
.closure-trail__when {
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  min-width: 6.5em;
}
.closure-trail__what { color: var(--ink-1, inherit); font-weight: 600; }
.closure-trail__detail { color: var(--ink-muted); }

/* Every recorded inspection (2026-08-15, restoring _visit_history). A table
   because it IS tabular — a run of visits with four numbers each — and the
   reader is comparing down a column, not reading prose. Scrolls inside its
   own box so a long history never makes the card scroll sideways. */
.card__details--visit-history { overflow-x: auto; }
.visit-hist {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}
.visit-hist th {
  text-align: left;
  font-size: var(--text-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--rule);
  padding: 4px 8px 4px 0;
}
.visit-hist td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--rule); }
.visit-hist tr:last-child td { border-bottom: 0; }
/* The high-priority count is the column a reader scans, so it carries the
   only colour in the table. */
.visit-hist__hp { font-weight: 700; }
.visit-hist__hp--high { color: #b3261e; }
.visit-hist__hp--moderate { color: #a15c00; }
.visit-hist__hp--low { color: var(--ink-muted); }
.visit-hist__disp { color: var(--ink-2); }

/* A caveat on a POSITIVE card. Muted, not alarming — the venue did improve;
   the point is that the reader gets the other half too. */
.card__basic-reason--caveat { color: var(--ink-muted); font-style: italic; }

/* Share buttons (2026-08-15). Deliberately quiet ON the page — the loud
   design lives in the card they produce, not in the control that makes it.
   A button that shouted here would compete with the data it is offering. */
.share-card__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: var(--s-2) 0;
}
.share-card__btn {
  appearance: none;
  min-height: 44px;               /* thumb target — this is a phone action */
  padding: 8px 16px;
  border: 2px solid var(--ink-1, #1a1a1a);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-1, #1a1a1a);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 700;
  cursor: pointer;
}
.share-card__btn:hover { background: var(--ink-1, #1a1a1a); color: var(--paper); }
.share-card__btn:focus-visible { outline: 3px solid var(--focus-ring-color, #0f172a); outline-offset: 2px; }
.share-card__btn[disabled] { opacity: .6; cursor: progress; }

/* License issued vs first inspected (2026-08-15). Two dates, equal weight,
   because the whole point is that they are different facts: a licence is
   permission to trade and an inspection is DBPR standing in the kitchen.
   PENDING is emphasised rather than muted -- an uninspected new licence is
   the informative case, not a missing value. */
.card__opening-dates {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  font-size: var(--text-sm);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.card__opening-label {
  color: var(--ink-muted);
  font-size: var(--text-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  font-weight: 700;
}
.card__opening-date--pending strong { color: var(--ink-1, inherit); }

/* Succession — who was here before, who is here now (2026-08-15).

   On the OVERVIEW face, because on a closure card the successor is the
   current state of the address rather than a historical footnote. Two rows
   at most, so a list rather than prose: the reader is scanning for a name,
   not reading a sentence. */
.card__succession {
  margin: 0;
  padding: var(--s-2) var(--s-3);
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 3px solid var(--rule);
  background: var(--paper);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.card__succession-label {
  color: var(--ink-muted);
  font-size: var(--text-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
  font-weight: 700;
}
.card__succession-name { font-weight: 700; color: var(--ink-1, inherit); }
/* The dates qualify the names rather than competing with them: the record
   gives a first and last SIGHTING, not a changeover date, and the wording
   says so. */
.card__succession-when { color: var(--ink-muted); font-weight: 400; }
/* Name & operator history sits on the INSPECTION face. The successor reads
   forward in time and the prior operators back, so they are differentiated
   in weight rather than colour — a colour split here would imply a risk
   judgement the block is not making. */
.card__details--dba-history { display: flex; flex-direction: column; gap: 4px; }
.dba-successor { font-weight: 700; }
.dba-prior { color: var(--ink-2); }
.dba-prior__alias,
.dba-prior__replaced { color: var(--ink-muted); }

.card__status-dossier { display: flex; flex-direction: column; gap: var(--s-2); }
.card__dossier-section {
  margin: 0;
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--rule);
  background: var(--paper);
}
.card__dossier-section > h4 {
  margin: 0 0 4px;
  color: var(--ink-muted);
  font-size: var(--text-xs);
  letter-spacing: .06em;
  text-transform: uppercase;
}
.card__dossier-section .card__turnover-contexts { margin: 0; }
.card__inspection-notes h4,
.card__news-comparison h4 {
  margin: 0 0 4px;
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.card__inspection-notes p,
.card__news-comparison p {
  margin: 0;
  line-height: 1.4;
}
.card__news-comparison p + p { margin-top: var(--s-1); }
.card__face .card-full-details {
  display: flex !important;
  flex-direction: column;
  gap: var(--s-2);
}
.card__face .card-full-details > * { margin-block: 0 !important; }
/* A wide screen is still one reading flow. The retired right-side metadata
   rail restricted the body to one grid cell and made short cards look padded
   or broken when the viewport grew. Keep metadata above the content and let
   every real block use the full card width. */
@media (min-width: 768px) {
  .card {
    display: block;
    grid-template-columns: none;
    grid-template-areas: none;
  }
  .card > .card__meta {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 4px 6px;
    min-width: 0;
    margin: 0 0 var(--s-2);
  }
  .card > :not(.card__meta),
  .card__body {
    grid-column: auto;
  }
}

/* Cards keep a neutral spine; section identity lives in the section chip
   and dimension heading, while inspection severity lives in the bar. */
.card--under-emergency-order,
.card--recent-failures,
.card--worst-offenders,
.card--bad-actors,
.card--most-improved,
.card--clean-plates,
.card--permanent-closures,
.card--lost-licenses,
.card--openings,
.card--new-licenses {
  border-left-width: 4px;
  border-left-color: var(--rule);
}

/* =================================================================
   Unified masthead controls — 2026-05-02
   One canonical source for the sticky masthead layout and the four
   bottom-row pills: metro, restaurant search, blog, and subscribe.
   Native select/search controls stay native; no custom SVG data-URI
   carets or native-control reset hacks.
   ================================================================= */
:root {
  /* Size tokens in rem (2026-08-21, fluid-type follow-up): these were px,
     so the masthead/jump-nav pill BOX stayed pinned to a fixed size while
     only the text inside it grew with the new fluid html font-size above
     -- text getting bigger inside an unchanging box is not what "buttons
     look small on a big monitor" asked for. rem ties the whole pill (box
     and text together) to the same root scale. Radius values stay in px
     deliberately -- corner rounding doesn't need to track type scale, and
     --pill-radius is already 999px (fully round) regardless of height. */
  --pill-h:        2.375rem;   /* 38px at the default 16px root */
  --pill-h-sm:     2rem;       /* 32px */
  --pill-radius:   999px;
  --pill-radius-soft: 4px;
  --pill-pad-x:    0.875rem;   /* 14px */
  --pill-pad-y:    0.375rem;   /* 6px */
  --pill-gap:      0.375rem;   /* 6px */
}

.metro-picker { padding-block: var(--s-1) !important; }
.metro-picker__inner {
  display: flex !important;
  flex-direction: column;
  align-items: stretch;
  gap: var(--pill-gap);
}

.metro-picker__brand {
  order: 1;
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  min-height: var(--pill-h);
  margin: 0;
  text-decoration: none;
  color: var(--red);
  white-space: nowrap;
  padding: 0 var(--pill-pad-x);
  border: 2px solid var(--red);
  border-radius: var(--pill-radius);
  background: var(--red-bg, #fdecec);
  transition: background .15s ease;
}
.metro-picker__brand:hover,
.metro-picker__brand:focus-visible {
  background: var(--red);
}
.metro-picker__brand:hover .metro-picker__brand-name,
.metro-picker__brand:focus-visible .metro-picker__brand-name {
  color: var(--paper);
}
.metro-picker__brand-name {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 32;
  font-weight: 800;
  font-size: clamp(1.35rem, 4vw, 1.8rem);
  letter-spacing: 0;
  line-height: 1;
  color: var(--red);
}
.metro-picker__brand-tagline {
  display: none;
  font-size: 0.78rem;
}
.metro-picker__freshness {
  order: 2;
  display: inline-flex;
  flex-wrap: wrap;          /* wrap "· twice-daily" instead of overflowing */
  margin: 0;
  max-width: 100%;
  font-size: 0.78rem;
  gap: 0.25rem;
}

/* Mobile masthead overflow guard (Option A, 2026-06-21). The brand
   cluster + freshness + site-nav pills can sum wider than a 320px
   viewport. Keep the inner column from ever forcing horizontal document
   scroll: the site-nav already scrolls internally (overflow-x:auto), so
   just make sure the masthead flex column never exceeds its track. */
.metro-picker__inner { max-width: 100%; }
.metro-picker .site-nav { max-width: 100%; min-width: 0; }

.metro-picker__select-wrap,
.metro-picker__search-wrap,
.metro-picker__signup,
.metro-picker__blog-cta {
  min-width: 0;
}
.metro-picker__select-wrap { order: 3; }
.metro-picker__search-wrap { order: 4; display: block; }
.metro-picker__blog-cta    { order: 5; }
.metro-picker__signup      { order: 6; display: block; }
.metro-picker__social-stub { display: none !important; }

/* ────────────────────────────────────────────────────────────────────
   UNIFIED COMMAND BAR (Option A, 2026-06-21)
   Metro picker + restaurant search inside ONE flex group that NEVER
   collapses or disappears at any width. This is the layout that retires
   the breakpoint grid-template-areas approach (whose track starvation
   caused the metro control to shrink to ~121px / vanish past 1440px).
   Pure flex: metro = clamped flex with a hard min-width floor so it can
   never collapse below a usable size; search = flex:1 1 auto. The bar
   wraps to two rows only on truly narrow viewports — it never hides a
   control. NO grid-template-areas for individual controls anywhere.
   ──────────────────────────────────────────────────────────────────── */
.metro-command {
  order: 3;                 /* sits where the metro picker used to */
  display: flex;
  flex-wrap: wrap;          /* nav + metro + search drop to rows when cramped */
  align-items: center;
  gap: var(--pill-gap);
  min-width: 0;
  width: 100%;
}
/* Nav segment (folded in 2026-06-22): the #111 cross-site pills now read as
   the FIRST element of the one command-bar widget. It keeps its own internal
   flex-wrap so the five pills wrap among themselves on narrow viewports, and
   as a command-bar flex child it can itself wrap to its own row above the
   metro + search when the bar is cramped. flex:0 1 auto = sizes to its pills,
   shrinks/wraps gracefully, never starves the metro/search floors. The
   internal overflow-x scroll from the base .site-nav rule is neutralised here
   (visible wrap is preferred inside the bar; the pills must never clip). */
.metro-command__nav {
  order: 0;
  flex: 0 1 auto;
  min-width: 0;
  overflow: visible;        /* prefer wrap over the base .site-nav scroll */
  padding-bottom: 0;
}
/* Metro segment: clamped width, with a real floor so it can NEVER be
   starved below ~14rem (well above the 200px usability bar) and is never
   display:none. */
.metro-command__metro {
  order: 1;
  flex: 0 1 16rem;
  min-width: 14rem;
}
/* Search segment: takes the remaining room, but keeps its own floor so it
   stays comfortably typeable. */
.metro-command__search {
  order: 2;
  flex: 1 1 18rem;
  min-width: 14rem;
}

/* Site destinations are useful, but on a phone they must not crowd out the
   actual briefing controls. The native disclosure keeps this progressively
   enhanced: without JS it is open; the mobile script closes it initially. */
.metro-mobile-menu {
  order: 0;
  flex: 0 1 auto;
  min-width: 0;
}
.metro-mobile-menu__summary {
  display: none;
}

/* Mobile header: orient, choose a metro, then read. This is intentionally a
   different information hierarchy from desktop—not a compressed desktop
   command wall. Brand/freshness share a light first row; metro + Near Me are
   the visible working controls; secondary destinations sit behind Explore. */
@media (max-width: 599px) {
  .metro-picker {
    padding: 6px var(--s-2) !important;
    /* The phone masthead is a compact command strip. Reserve the larger
       targets for card actions; these persistent controls are deliberately
       34px high so they do not dominate the first viewport. */
    --pill-h: 34px;
  }
  .metro-picker__inner {
    display: grid !important;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "brand freshness"
      "command command";
    align-items: center;
    gap: 6px 8px;
  }
  .metro-picker__brand {
    grid-area: brand;
    order: unset;
    min-height: 32px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
  }
  .metro-picker__brand-name {
    font-size: 1.35rem;
  }
  .metro-picker__freshness {
    grid-area: freshness;
    order: unset;
    justify-content: flex-end;
    max-width: 10rem;
    margin: 0;
    font-size: 0.68rem;
    line-height: 1.2;
    text-align: right;
  }
  .metro-picker__freshness-edition {
    display: none;
  }
  .metro-command {
    grid-area: command;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "metro near"
      "menu menu"
      "search search";
    align-items: stretch;
    gap: 6px;
  }
  .metro-mobile-menu {
    grid-area: menu;
    width: 100%;
  }
  .metro-mobile-menu__summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 30px;
    padding: 0 10px;
    border: 1px solid var(--rule);
    border-radius: 6px;
    background: var(--paper-2);
    color: var(--ink-muted);
    cursor: pointer;
    font-size: var(--text-xs);
    font-weight: 700;
    list-style: none;
  }
  .metro-mobile-menu__summary::-webkit-details-marker { display: none; }
  .metro-mobile-menu__summary::after {
    content: "+";
    color: var(--red);
    font-size: 1rem;
    line-height: 1;
  }
  .metro-mobile-menu[open] .metro-mobile-menu__summary::after { content: "−"; }
  .metro-mobile-menu .site-nav.metro-command__nav,
  .metro-command__nav.site-nav {
    display: flex !important;
    flex-wrap: wrap !important;
    overflow: visible !important;
    padding: 6px 0 0;
  }
  .metro-mobile-menu .site-nav.metro-command__nav .site-nav__link {
    min-height: 32px !important;
    padding: 4px 8px !important;
    font-size: 0.78rem;
  }
  .metro-command__metro {
    grid-area: metro;
    min-width: 0;
  }
  .metro-command__near-me {
    grid-area: near;
    min-height: var(--pill-h);
    padding-inline: 10px;
  }
  .metro-picker__search-wrap,
  .metro-command__search {
    grid-area: search;
    min-width: 0;
  }
}

/* Mobile card scan: Simplified means a decision surface, not a smaller version
   of the whole dossier. Keep the title, current classification, date,
   score/trend and any one-line violation finding in view. Count chips and all
   supporting evidence are one native disclosure away; Full details opens the
   exact same content on demand. */
.card__mobile-details-summary {
  display: none;
}
@media (max-width: 767px) {
  .dimensions.mode-basic .card {
    padding: 10px 12px !important;
    row-gap: 6px !important;
  }
  .dimensions.mode-basic .risk-card-badges {
    gap: 3px;
    padding: 2px 0;
  }
  .dimensions.mode-basic .dimension-badge {
    padding: 2px 6px;
    font-size: 0.68rem;
  }
  .dimensions.mode-basic .card__stats {
    gap: 6px var(--s-2) !important;
  }
  /* The primary classification and dated observation are the scan layer.
     Regulatory and historical context remains available in More details or
     Full details, rather than competing with the decision on every card. */
  .dimensions.mode-basic .card__stats .card__stat:nth-child(n + 3) {
    display: none;
  }
  .dimensions.mode-basic .card.card--mobile-expanded
    .card__stats .card__stat:nth-child(n + 3) {
    display: flex;
  }
  .dimensions.mode-basic .card__severity {
    margin: 6px 0 2px;
  }
  .dimensions.mode-basic .card__mobile-details {
    margin-top: 2px;
  }
  .dimensions.mode-basic .card__mobile-details-summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 34px;
    color: var(--navy);
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: 700;
    list-style: none;
  }
  .dimensions.mode-basic .card__mobile-details-summary::-webkit-details-marker {
    display: none;
  }
  .dimensions.mode-basic .card__mobile-details-summary::after {
    content: "+";
    color: var(--red);
    font-size: 1.1rem;
    line-height: 1;
  }
  .dimensions.mode-basic .card__mobile-details[open]
    .card__mobile-details-summary::after {
    content: "−";
  }
  /* The global basic-density rule hides this block. A phone reader who opens
     one card explicitly overrides it for that card only. */
  .dimensions.mode-basic .card__mobile-details[open] .card-full-details {
    display: block;
  }
  .dimensions.mode-full .card__mobile-details-summary {
    display: none;
  }
}

.metro-picker__select-wrap,
.metro-picker__search-wrap .metro-search,
.metro-picker__blog-cta,
.metro-picker__signup-form {
  box-sizing: border-box;
  width: 100%;
  max-width: none;
  min-height: var(--pill-h);
  border: 1px solid var(--rule);
  border-radius: var(--pill-radius);
  display: inline-flex;
  align-items: center;
  gap: var(--pill-gap);
  margin: 0;
  padding: 0 var(--pill-pad-x);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1;
  white-space: nowrap;
}
/* All four masthead pills share the same rose background per
   operator 2026-05-02: "use same rose background for all ux pills
   in the header". Visual unity > role differentiation here — the
   metro/resto pickers + blog/subscribe CTAs all read as one palette. */
/* Operator 2026-05-04: pick-a-metro / find-a-resto / blog cta /
   subscribe form — red background with white text, not the pink
   tint they had before. Inputs inside need their text + placeholder
   colors flipped to white-ish too. */
.metro-picker__select-wrap,
.metro-picker__search-wrap .metro-search,
.metro-picker__blog-cta,
.metro-picker__signup-form {
  background: var(--dim-red-alert);
  border-color: var(--dim-red-alert);
  color: var(--paper);
}
.metro-picker__select-label,
.metro-picker__search-wrap .metro-search__label,
.metro-picker__blog-cta,
.metro-picker__signup-pitch,
.metro-picker__signup-kicker,
.metro-picker__signup-tag {
  color: var(--paper) !important;
}
/* Operator 2026-05-04: metro selection text + find-a-resto typed-in
   query + subscribe email all read in YELLOW on the red picker
   background. #FFEA00 = ~6.5:1 contrast on #dc2626 (AAA normal-text)
   and pops against the red far better than the previous white. */
.metro-picker__select,
.metro-picker__search-wrap .metro-search__input,
.metro-picker__signup-input {
  color: #FFEA00;
  font-weight: 700;
  caret-color: #FFEA00;
}
.metro-picker__search-wrap .metro-search__input::placeholder,
.metro-picker__signup-input::placeholder {
  color: rgba(255, 234, 0, 0.78);
}
.metro-picker__select option {
  color: var(--ink);  /* native dropdown options stay paper-on-ink */
  background: var(--paper);
}

.metro-picker__select-label,
.metro-picker__search-wrap .metro-search__label {
  flex: 0 0 auto;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  white-space: nowrap;
  line-height: 1;
}
.metro-picker__search-wrap .metro-search {
  /* Allow the input to drop onto its own line below the label + Clear
     when the bar is narrow, instead of being crushed to a few px. The
     input keeps a comfortable min-width floor (the inset-field rule
     below pins min-width:10em) so it is always typeable; on roomy rows
     everything stays on one line. (Option A unified command bar.) */
  flex-wrap: wrap;
}
.metro-picker__select,
.metro-picker__search-wrap .metro-search__input {
  box-sizing: border-box;
  flex: 1 1 auto;
  min-width: 0;
  height: calc(var(--pill-h) - 10px);
  padding: 0 4px;
  border: 0;
  border-radius: var(--pill-radius);
  background: transparent;
  /* Operator 2026-05-04: yellow on red picker — was overriding the
     yellow rule above with `var(--ink)` (black). Strip native chrome
     with appearance:none so macOS Safari respects the color too. */
  color: #FFEA00;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: normal;
  outline: none;
}
/* Custom dropdown chevron now that we stripped native appearance. */
.metro-picker__select {
  background-image:
    linear-gradient(45deg, transparent 50%, #FFEA00 50%),
    linear-gradient(-45deg, transparent 50%, #FFEA00 50%);
  background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 22px;
}
.metro-picker__select {
  cursor: pointer;
}
.metro-picker__search-wrap .metro-search__input {
  cursor: text;
}
/* Operator 2026-05-04: belt-and-suspenders bold on find-a-resto.
   Some browsers render <input> with their own font-weight default that
   was beating the cascade above on certain devices. Force it. */
.metro-search__input,
.metro-picker__search-wrap .metro-search__input,
.metro-search__input::placeholder,
.metro-picker__search-wrap .metro-search__input::placeholder {
  font-weight: 700 !important;
}

/* Operator 2026-06-21: you must clearly SEE what you type in Find-a-Resto.
   The yellow-on-red input was hard to read while typing (fine for the static
   metro value, not for live typing), and min-width:0 let it collapse when the
   status + Clear crowded the bar. Give the input an INSET LIGHT FIELD with
   dark-red bold text + a real min-width so the query is always legible. */
.metro-picker__search-wrap .metro-search__input {
  /* Floor + grow (Option A unified command bar): declared AFTER the
     grouped `.metro-picker__select, … .metro-search__input { min-width:0 }`
     rule, so this floor WINS the cascade at every breakpoint. The form
     pill (.metro-search) is flex-wrap:wrap, so when the row is too tight
     the whole input drops onto its own line and gets the full pill width;
     this floor guarantees it is never crushed below 10em (typeable on a
     320px phone). Search is therefore always visible AND usable. */
  flex: 1 1 10em;
  min-width: 10em;
  background: rgba(255, 255, 255, 0.97) !important;
  color: #7f1d1d !important;
  caret-color: #7f1d1d !important;
  border: 2px solid #FFEA00 !important;   /* clear field edge on the red bar */
  border-radius: 7px;
  /* leading magnifier so it unmistakably reads as a SEARCH box */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237f1d1d' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='21' y1='21' x2='16.5' y2='16.5'/%3E%3C/svg%3E") !important;
  background-repeat: no-repeat !important;
  background-position: 9px 50% !important;
  background-size: 16px 16px !important;
  padding: 0 10px 0 32px;
  height: calc(var(--pill-h) - 6px);
}
.metro-picker__search-wrap .metro-search__input::placeholder {
  color: #8a5050 !important;
  font-weight: 600 !important;
  opacity: 1;
}
.metro-picker__search-wrap .metro-search__input::-webkit-search-decoration,
.metro-picker__search-wrap .metro-search__input::-webkit-search-cancel-button,
.metro-picker__search-wrap .metro-search__input::-webkit-search-results-button,
.metro-picker__search-wrap .metro-search__input::-webkit-search-results-decoration {
  display: none;
}
.metro-picker__select-wrap:focus-within,
.metro-picker__search-wrap .metro-search:focus-within,
.metro-picker__signup-form:focus-within,
.metro-picker__blog-cta:focus-visible {
  border-color: var(--ink);
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 4px var(--ink);
  outline: none;
}
.metro-picker__search-wrap .metro-search__status,
.metro-picker__signup-status {
  display: none;
}
.metro-picker__search-wrap .metro-search__status:not(:empty),
.metro-picker__signup-status:not(:empty) {
  display: block;
  flex-basis: 100%;
  margin: var(--s-1) 0 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-muted);
  white-space: normal;
}

.metro-picker__blog-cta {
  text-decoration: none;
  justify-content: flex-start;
  transition: background 120ms ease, color 120ms ease;
}
.metro-picker__blog-cta:hover,
.metro-picker__blog-cta:focus-visible {
  background: var(--red);
  color: var(--paper);
}
.metro-picker__blog-cta-avatar {
  /* NOT resized with the others on 2026-08-17, deliberately. Nothing emits this
     class: the only reference outside this rule is a querySelector that returns
     early when the element is absent, and no template in riskyeats/templates
     produces it. Raising a size here would have looked like a fix and changed
     nothing on the site -- so the number stays as found, and this note is here
     so the next person does not spend the same ten minutes. */
  width: 24px !important;
  height: 24px !important;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
  background: var(--paper-3);
}
.metro-picker__blog-cta-label {
  display: inline-flex;
  flex-direction: column;
  line-height: 1;
  gap: 1px;
}
.metro-picker__blog-cta-kicker {
  font-size: 0.7em;
  color: var(--red);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 700;
}
.metro-picker__blog-cta:hover .metro-picker__blog-cta-kicker,
.metro-picker__blog-cta:focus-visible .metro-picker__blog-cta-kicker {
  color: var(--paper);
}
.metro-picker__blog-cta-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 0.95em;
}

.metro-picker__signup-pitch,
.metro-picker__signup-kicker,
.metro-picker__signup-tag {
  display: none !important;
}
.metro-picker__signup-form {
  padding: 0 4px 0 var(--pill-pad-x);
}
.metro-picker__signup-input {
  flex: 1 1 12rem;
  min-width: 0;
  height: calc(var(--pill-h) - 12px);
  padding: 0 10px;
  border: 0;
  border-radius: var(--pill-radius);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  outline: none;
}
.metro-picker__signup-input::placeholder { color: var(--ink-muted); }
.metro-picker__signup-submit {
  flex: 0 0 auto;
  height: calc(var(--pill-h) - 12px);
  padding: 0 14px;
  border: 1px solid var(--paper);
  border-radius: var(--pill-radius);
  /* Submit button sits ON the red signup-form bg now — invert: paper
     bg with red text reads as the canonical submit affordance. */
  background: var(--paper);
  color: #dc2626;
  font-family: var(--font-body);
  font-weight: 800;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  cursor: pointer;
}
.metro-picker__signup-submit:hover,
.metro-picker__signup-submit:focus-visible {
  background: #fee2e2;
  color: #6B5B4E;
  outline: none;
}

@media (min-width: 600px) {
  .metro-picker__brand-tagline { display: block; }
}
@media (min-width: 1024px) {
  /* Desktop masthead. Per Stuart Skolnik feedback 2026-05-03: 4 pills
     in one row squeezed the Find-a-Resto input too narrow for typing.
     Now 2 pills per row at 1024-1440px (metro+search on row 1,
     blog+signup on row 2), then 4-up at >=1440px where there\u0027s
     genuine horizontal headroom. */
  /* UNIFIED COMMAND BAR flex layout (Option A, 2026-06-21). This
     REPLACES the previous grid-template-areas approach that starved the
     metro track and made "Pick a Metro" vanish past 1440px. There are NO
     grid-template-areas and NO per-control grid-area assignments here. */
  .metro-picker__inner {
    max-width: min(1240px, 100% - 2 * var(--s-4));
    display: flex !important;
    flex-flow: row wrap;
    justify-content: flex-start;
    align-items: center;
    column-gap: var(--pill-gap);
    row-gap: var(--pill-gap);
  }
  .metro-picker__brand     { order: 0; flex: 0 0 auto; align-self: center; }
  .metro-picker__freshness { order: 1; flex: 1 1 auto; }
  /* The 5 cross-site pills are now FOLDED INTO the command bar (2026-06-22),
     not a top-row sibling of brand/freshness. Inside the bar they must read
     FIRST and never collide with the metro/search orders, so pin the in-bar
     nav to order:0 here (this desktop rule is more specific than the base
     .metro-command__nav rule and would otherwise re-order it). Any stray
     .site-nav that is NOT inside the command bar keeps the old top-row
     position. */
  .metro-command .metro-command__nav { order: 0; flex: 0 1 auto; }
  .metro-picker__inner > .site-nav   { order: 2; flex: 0 0 auto; }
  /* Command bar = its own full-width row at 1024-1439px so metro+search
     both get generous width and never squeeze each other to a stub. */
  .metro-command           { order: 3; flex: 1 1 100%; width: 100%; min-width: 0; }
  .metro-picker__signup    { order: 4; flex: 1 1 auto; }
  /* Metro segment keeps its clamped width AND its real floor on desktop —
     it must never be reset to min-width:0 (that was the failure class:
     the metro control could then be starved to a stub). It stays a peer
     of search inside the command bar, never display:none, never <14rem. */
  .metro-command__metro {
    flex: 0 1 16rem;
    min-width: 14rem;
  }
  /* Other pill chrome (search form, signup form) fills the width its flex
     parent grants — no fixed widths fighting the flex sizing. */
  .metro-picker__search-wrap .metro-search,
  .metro-picker__signup-form {
    width: 100%;
    min-width: 0;
  }
  .metro-picker__select,
  .metro-picker__signup-input {
    width: auto;
    flex: 1 1 auto;
    min-width: 0;
  }
}
@media (min-width: 1440px) {
  /* Wide desktop / ultrawide — single row, all clusters fit:
       [brand] [freshness] [site-nav] [ metro | search ] [signup]
     The command bar drops back from the 1024px full-width row to an
     auto-grown share of the single row. It keeps flex-grow so it absorbs
     the extra ultrawide width; metro + search keep their own min-width
     floors (.metro-command__metro min-width:14rem) and can never collapse
     however wide the viewport gets. No grid, no named areas, no track to
     starve. */
  .metro-command { flex: 1 1 36rem; width: auto; }
}

/* Social share + follow — top-of-masthead pill row, always visible */
.metro-picker__social,
.metro-picker__social--top {
  display: inline-flex !important;
  align-items: center;
  gap: var(--pill-gap);
  flex-wrap: wrap;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  height: auto;
}
.metro-picker__social .metro-picker__social-label { display: none; }
.metro-picker__social .a2a_kit { display: inline-flex; gap: 4px; }
.metro-picker__social .a2a_kit > a {
  width: var(--pill-h);
  height: var(--pill-h);
  border: 1px solid var(--rule);
  border-radius: var(--pill-radius);
  background: var(--paper);
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
}
.metro-picker__social .a2a_kit > a:hover { background: var(--paper-2); border-color: var(--ink); }
.metro-picker__social .a2a_kit > a img,
.metro-picker__social .a2a_kit > a svg {
  width: 18px !important;
  height: 18px !important;
  display: block;
}
.metro-picker__social .metro-picker__follow {
  display: inline-flex;
  gap: 4px;
}
.metro-picker__social .follow-link {
  width: var(--pill-h);
  height: var(--pill-h);
  border: 1px solid var(--rule);
  border-radius: var(--pill-radius);
  background: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
}
.metro-picker__social .follow-link:hover { background: var(--ink); color: var(--paper); }

/* (Legacy compact-mode social-visibility override removed 2026-05-02 —
   social block now lives in .riskyeats-toolbar between the jump-nav
   and the metro panel, not in the masthead. Codex MED.) */

/* Jump nav — pill row, same metrics as masthead */
.jump-nav__link {
  height: var(--pill-h);
  padding: 0 var(--pill-pad-x);
  border-radius: var(--pill-radius);
  font-size: var(--text-sm);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  gap: var(--pill-gap);
  white-space: nowrap;
}

/* Stat-band — pills */
.stat-tile {
  height: var(--pill-h);
  padding: 0 var(--pill-pad-x);
  border-radius: var(--pill-radius);
  display: inline-flex;
  align-items: center;
  gap: var(--pill-gap);
  min-height: 0;
  border-left-width: 1px !important;
}
.stat-tile__label {
  font-size: var(--text-sm);
  line-height: 1;
}
.stat-tile__value {
  font-size: 1.1em;
  line-height: 1;
}
.stat-band {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;       /* center stat tiles when the row wraps — operator 2026-05-02 */
  gap: var(--pill-gap);
  padding: var(--badge-pad-y) var(--badge-pad-x) !important;
  background: transparent !important;
  border: 0 !important;
}
.stat-band__heading,
.stat-band__metro { display: none; }

/* =================================================================
   SLIM FOOTER — 2026-05-02
   Compact one-line strips replacing the stacked legal/data-providers
   blocks. Single "details" handles full legal text on demand.
   ================================================================= */
.site-footer {
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--rule);
  background: var(--paper-2);
}
.site-footer__inner {
  max-width: var(--measure-grid);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  align-items: center;
  text-align: center;
}
.footer-freshness {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
}
.footer-links a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.footer-links a:hover { color: var(--red); }
.footer-links span[aria-hidden] { color: var(--ink-muted); }

.footer-legal {
  width: 100%;
  max-width: 75ch;
  margin: 0;
}
.footer-legal > summary {
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  text-align: center;
  list-style: none;
}
.footer-legal > summary::-webkit-details-marker { display: none; }
.footer-legal > summary::after { content: " ▾"; }
.footer-legal[open] > summary::after { content: " ▴"; }
.footer-legal__body {
  padding-top: var(--s-2);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  line-height: 1.55;
  color: var(--ink);
  text-align: left;
}
.footer-legal__body p { margin: 0 0 var(--s-2); }
.footer-legal__body p:last-child { margin: 0; }

.data-providers-strip {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  align-items: center;
}
.data-providers-strip__label {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.data-providers-strip a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.data-providers-strip a:hover { color: var(--red); }

.copyright {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* =================================================================
   GLOBAL TYPOGRAPHY PASS — 2026-05-02
   Operator: "lets see if we can improve global typography"
   Target audience is 55+; favor body font (Atkinson Hyperlegible)
   for prose, display font (Bricolage Grotesque) only for the bigger
   headings + numerals. Every paragraph at 18px body / 1.6 line-height.
   Heading hierarchy: h1 28px, h2 22.5px, h3 18px-bold, h4 16px-bold.
   ================================================================= */

/* Body prose anywhere on the page — paragraphs and list items inherit
   the 55+-friendly 18px / 1.6 / Atkinson family unless something
   inside a card or header overrides. */
body, p, li, dd {
  font-family: var(--font-body);
}
.metro-panel p,
.metro-panel li,
.metro-panel dd,
.dimension__narrative-prose,
.dimension__intro p,
.briefing__paragraph,
.post-section__voice,
.post-lede {
  font-size: var(--text-base);
  line-height: 1.6;
}

/* Heading hierarchy — display font, weighted, balanced text-wrap */
.dimension__heading {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 32;
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.2;
  letter-spacing: -0.005em;
  text-wrap: balance;
}
.metro-briefing > h2,
.briefing > h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.2;
}

/* Card name — body font at 18px so the 55+ reader doesn't squint.
   Was previously text-md display which read as too-big for a card
   that's already constrained on horizontal real estate. */
.card__name {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 32;
  font-weight: 700;
  /* Venue name is the card's subject, so it is sized like one (operator
     2026-08-17: "the restaurant name needs to be increased several point
     sizes"). 1.42-1.7rem -> 1.8-2.15rem. */
  font-size: clamp(1.8rem, 1.9vw, 2.15rem);
  line-height: 1.25;
  letter-spacing: -0.005em;
}
/* HIGH-CONTRAST, NOT THE DIMENSION ACCENT (operator 2026-08-17: "I don't
   think we should use the same color text as the dimension, it should be a
   high contrast color like black").

   Every dimension used to repaint the venue name in its own accent --
   #dc2626 for emergency orders, #6B5B4E for closures, #64748b for ghost
   licences and eleven more. Those were chosen to clear 4.5:1 on white, so
   each was legible on its own, but the NAME is the one thing a reader
   scans for across every dimension on the page, and painting it fourteen
   different colours made the page's most important text its least
   consistent. --ink is #111111, 18.9:1 (AAA).

   The accent survives where it belongs: the dimension's links, CTAs and
   source badges are untouched, so each block keeps its identity without
   spending it on the restaurant's name.

   `a` is listed explicitly because the name is often wrapped in one and an
   anchor takes the UA/link colour rather than inheriting from its parent. */
.card__name,
.card__name a {
  color: var(--ink);
}

/* Card secondary text — bump from text-xs to text-sm for readability.
   xs (14px) was too small for the 55+ baseline. */
.card__location,
.card__counts,
.card__disposition,
.card__report-link {
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* Stat tile + jump-nav labels — keep at text-sm; was inconsistent
   between text-xs and text-sm depending on which historical block
   set them. */
.stat-tile__label,
.stat-tile__value {
  font-size: var(--text-sm);
}
.jump-nav__link .jump-nav__label {
  font-size: var(--text-sm);
  font-weight: 700;
}
.jump-nav__link .jump-nav__count {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  margin-left: 4px;
  opacity: 0.85;
}

/* Footer + masthead small text — unify at text-xs (14px) so all
   incidental labels read as one register. */
.footer-freshness,
.footer-links,
.data-providers-strip,
.metro-picker__freshness {
  font-size: var(--text-xs);
}

/* =================================================================
   WCAG typography pass — 2026-05-02
   ================================================================= */

/* Global focus-visible default. Any interactive element that doesn't
   ship its own focus style gets a clear ink outline. WCAG 2.4.7
   requires a visible focus indicator on every keyboard-reachable
   element; this is the safety net. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Touch pointers (phones, tablets) — bump pill min-height to AAA's
   44px target. The masthead controls, jump-nav, and toolbar all
   inherit through the existing `var(--pill-h)`. */
/* (Coarse-pointer global --pill-h bump removed — was forcing every
   pill on the page to 44px and stretching the masthead pills into
   tall ovals on widescreen + mobile. We hit 44px tap targets via
   per-element min-height where needed, not via a global var bump.) */
/* Card-body text bumps — these pieces of prose were sitting at
   text-xs (~14px) which fails the operator's 16px-minimum-for-body
   rule for the 55+ audience. Lift them to text-sm where readability
   matters; truly incidental labels (kicker tags, status timestamps)
   stay at xs. */
.card__location {
  font-size: var(--text-sm);
}
.card__counts {
  font-size: var(--text-sm);
  line-height: 1.55;
}
.card__disposition {
  font-size: var(--text-sm);
}

/* Body prose line-height — bump from any 1.4 hits to ≥1.55 so the
   55+ audience reads dense paragraphs without losing place. */
.card__counts,
.dimension__intro p,
.footer-legal__body p {
  line-height: 1.55;
}

/* (Legacy .metro-picker__social--hidden hide-rule removed 2026-05-02 —
   the placeholder div now uses the [hidden] HTML attribute, which
   does the same thing without a CSS selector. Codex MED.) */

/* =================================================================
   Fixed social toolbar — sits BETWEEN jump nav and metro panel.
   Single horizontal pill row, always visible, no compact-mode hide.
   ================================================================= */
.riskyeats-toolbar {
  max-width: var(--measure-grid);
  margin: 0 auto;
  padding: var(--s-2) var(--s-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--pill-gap);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: var(--paper-2);
}
.riskyeats-toolbar__label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
}
.riskyeats-toolbar__divider { color: var(--ink-muted); }
/* Wrap the share icons (Option A masthead pass, 2026-06-21): on a 320px
   phone the static fallback share buttons sum wider than the toolbar's
   content box and would force the document into horizontal scroll. Let
   them wrap onto a second row + cap the kit to its parent so the page
   never overflows at any width. */
.riskyeats-toolbar .a2a_kit { display: inline-flex; flex-wrap: wrap; max-width: 100%; gap: 4px; }
.riskyeats-toolbar .a2a_kit > a {
  width: var(--pill-h);
  height: var(--pill-h);
  border: 1px solid var(--rule);
  border-radius: var(--pill-radius);
  background: var(--paper);
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
}
.riskyeats-toolbar .a2a_kit > a:hover { background: var(--ink); border-color: var(--ink); }
.riskyeats-toolbar .a2a_kit > a img,
.riskyeats-toolbar .a2a_kit > a svg {
  width: 18px !important;
  height: 18px !important;
  display: block;
}
.riskyeats-toolbar__follow {
  display: inline-flex;
  gap: 4px;
}
.riskyeats-toolbar__follow .follow-link {
  width: var(--pill-h);
  height: var(--pill-h);
  border: 1px solid var(--rule);
  border-radius: var(--pill-radius);
  background: var(--paper);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
}
.riskyeats-toolbar__follow .follow-link:hover { background: var(--ink); color: var(--paper); }
/* CACHE-BUST 20260502T190737 */

/* ---- Dimension expander head — 5-bucket severity palette ----------
   Operator 2026-05-02 (rev 2): cleaner functional grouping.
     RED      = UEO active enforcement
     ORANGE   = Near Miss (cited but operating)
     MAROON   = Chronic pattern
     GREEN    = Positive (clean / new license)
     NAVY     = License admin (lost license)
     CHARCOAL = Closed / off-cadence
*/
.dimension-block > .dimension > summary.dimension__head {
  padding: var(--s-2) var(--s-3);
  border-radius: 4px;
  border-bottom: 0;
  margin: 0 0 var(--s-3);
  cursor: pointer;
  background: #2B2B2B;
  color: var(--paper);
  transition: filter 120ms ease;
}
.dimension-block > .dimension > summary.dimension__head:hover {
  filter: brightness(1.08);
}
.dimension-block > .dimension > summary.dimension__head,
.dimension-block > .dimension > summary.dimension__head *,
.dimension-block > .dimension > summary.dimension__head .dimension__heading,
.dimension-block > .dimension > summary.dimension__head .dimension__count,
.dimension-block > .dimension > summary.dimension__head .dimension__expand,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue--open,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue--closed,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-chevron {
  color: inherit !important;
}
/* Yellow/orange variants need dark text for AAA contrast on the
   warmer backgrounds. Recent-failures uses ORANGE which still passes
   on white text but the chronic-pattern + UEO RED + deep MAROON
   need lighter weight for the small "Show N records" cue so it
   reads at glance. */
.dimension-block > .dimension > summary.dimension__head .dimension__count,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue {
  opacity: 0.92;
}
.dimension-block[data-dim="under-emergency-order"] > .dimension > summary.dimension__head {
  background: var(--dim-red-alert);
}
.dimension-block[data-dim="recent-failures"] > .dimension > summary.dimension__head {
  background: var(--dim-near-miss);
  color: var(--paper);
}
.dimension-block[data-dim="worst-offenders"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="bad-actors"] > .dimension > summary.dimension__head {
  background: var(--dim-worst-offenders);
}
.dimension-block[data-dim="worsts"] > .dimension > summary.dimension__head {
  background: #ff5722;
}
.dimension-block[data-dim="most-improved"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="clean-plates"] > .dimension > summary.dimension__head {
  background: var(--dim-most-improved);
}
.dimension-block[data-dim="permanent-closures"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="closures"] > .dimension > summary.dimension__head {
  background: var(--dim-closures);
}
.dimension-block[data-dim="ghost-licenses"] > .dimension > summary.dimension__head {
  background: var(--dim-license-paper);
}
.dimension-block[data-dim="lost-licenses"] > .dimension > summary.dimension__head {
  background: var(--dim-owner-changed);
}
.dimension-block[data-dim="openings"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="new-licenses"] > .dimension > summary.dimension__head {
  background: var(--dim-openings);
}
.dimension-block[data-dim="chain-activity"] > .dimension > summary.dimension__head {
  background: var(--dim-chain-activity);
}

/* ---- Jump-nav pills — match section bar colors (5-bucket rev2) ---
   Same palette as dimension__head. Solid color rest state, brightness
   bump on hover, outline on aria-current="location" (scrollspy).
*/
.jump-nav__link[data-dim="under-emergency-order"] {
  color: var(--paper); background: #dc2626; border-color: #dc2626;
}
.jump-nav__link[data-dim="recent-failures"] {
  color: var(--paper) !important; background: #F97316; border-color: #F97316;
}
.jump-nav__link[data-dim="worst-offenders"],
.jump-nav__link[data-dim="bad-actors"] {
  color: var(--paper); background: #8B1818; border-color: #8B1818;
}
.jump-nav__link[data-dim="most-improved"],
.jump-nav__link[data-dim="clean-plates"] {
  color: var(--paper); background: #16a34a; border-color: #16a34a;
}
.jump-nav__link[data-dim="lost-licenses"] {
  color: var(--paper); background: #1A3D6D; border-color: #1A3D6D;
}
.jump-nav__link[data-dim="openings"],
.jump-nav__link[data-dim="new-licenses"] {
  color: var(--paper); background: #06b6d4; border-color: #06b6d4;
}
.jump-nav__link[data-dim="ghost-licenses"] {
  color: var(--paper); background: #64748b; border-color: #64748b;
}
.jump-nav__link[data-dim="chain-activity"] {
  color: var(--paper); background: #9333ea; border-color: #9333ea;
}
.jump-nav__link[data-dim="worsts"] {
  color: var(--paper); background: #ff5722; border-color: #ff5722;
}
.jump-nav__link[data-dim="permanent-closures"],
.jump-nav__link[data-dim="closures"] {
  color: var(--paper); background: #6B5B4E; border-color: #6B5B4E;
}
/* Operator 2026-05-04: removed duplicate hover rule (was
   `filter: brightness(1.12)`). Pill hover lives once at line ~2783
   with `box-shadow: 0 0 0 2px var(--ink)` — filters were causing
   pills to "disappear" on hover in some stacking contexts. */
.jump-nav__link[data-dim][aria-current="location"] {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}
.jump-nav__link[data-dim] .jump-nav__count {
  color: inherit;
  opacity: 0.85;
}

/* ---- Stat band — mobile-safe stacked list -------------------------
   Operator 2026-05-02 (eve): the pill-row layout corrupts on mobile
   because each pill has its own width + the row-wrap happens mid-tile
   when label + 5-digit number can't fit a 50%-screen track. On
   ≤640px screens drop the pill chrome entirely and render as a clean
   2-column key/value list — body font, tabular numerals, no overflow
   risk. Desktop keeps the pill-row look unchanged.
*/
@media (max-width: 640px) {
  .stat-band {
    display: block !important;
    padding: var(--badge-pad-y) var(--badge-pad-x) !important;
    background: var(--paper-2) !important;
    border: 1px solid var(--rule) !important;
    border-radius: var(--badge-radius-tag) !important;
  }
  .stat-band__heading,
  .stat-band__metro { display: block !important; }
  .stat-band__heading {
    font-family: var(--font-body);
    font-size: var(--badge-font);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-muted);
    text-align: center;
    margin: 0 0 var(--s-2);
  }
  .stat-grid,
  .stat-band > .stat-tile,
  .stat-band {
    /* Be explicit: any descendant tile becomes a row regardless of
       which intermediate wrapper class the renderer ships. */
  }
  .stat-grid {
    display: flex !important;
    flex-direction: column !important;
    gap: 0 !important;
  }
  .stat-tile {
    display: flex !important;
    flex-direction: row !important;
    align-items: baseline !important;
    justify-content: space-between !important;
    width: 100% !important;
    min-height: 0 !important;
    height: auto !important;
    padding: 6px var(--s-2) !important;
    border: 0 !important;
    border-bottom: 1px solid var(--rule) !important;
    border-left: 4px solid var(--accent, var(--ink-muted)) !important;
    border-radius: 0 !important;
    background: transparent !important;
    gap: var(--s-2) !important;
  }
  .stat-tile:last-child {
    border-bottom: 0 !important;
  }
  .stat-tile__label {
    font-family: var(--font-body) !important;
    font-size: 0.78rem !important;
    font-weight: 700 !important;
    letter-spacing: 0.04em !important;
    color: var(--ink) !important;
    line-height: 1.3 !important;
    flex: 1 1 auto !important;
    min-width: 0 !important;
    text-align: left !important;
  }
  .stat-tile__value {
    font-family: var(--font-body) !important;
    font-variation-settings: normal !important;
    font-weight: 800 !important;
    font-size: 0.95rem !important;
    line-height: 1.2 !important;
    color: var(--ink) !important;
    font-variant-numeric: tabular-nums !important;
    white-space: nowrap !important;
    flex: 0 0 auto !important;
  }
  /* Per-dim accent left border on mobile (matches the bucket palette). */
  .stat-tile--under-emergency-order { border-left-color: #dc2626 !important; }
  .stat-tile--recent-failures       { border-left-color: #F97316 !important; }
  .stat-tile--worst-offenders,
  .stat-tile--bad-actors            { border-left-color: #8B1818 !important; }
  .stat-tile--most-improved,
  .stat-tile--clean-plates          { border-left-color: #16a34a !important; }
  .stat-tile--openings,
  .stat-tile--new-licenses          { border-left-color: #06b6d4 !important; }
  .stat-tile--lost-licenses         { border-left-color: #1A3D6D !important; }
  .stat-tile--permanent-closures    { border-left-color: #6B5B4E !important; }
}

/* ---- Font-size selector (upper-left, dynamic) -----------------------
   Three sizes scale every text-* CSS variable. Selector is fixed-pos
   upper-left so it's always reachable without disrupting masthead.
   Stored in localStorage as riskyeats:fz.
*/
.fz-selector {
  position: fixed;
  top: var(--s-2);
  right: var(--s-2);
  z-index: 200;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 999px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
  font-family: var(--font-body);
}
.fz-selector__label {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: 4px;
}
.fz-selector__btn {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  /* 2px -> 4px vertical (operator 2026-08-21, mobile copy-density audit:
     desktop measured 15.7-19.4px including the intentional "MED #10"
     0.85 desktop scale-down a few hundred lines below, kept as-is here
     -- this control is deliberately compact so it doesn't compete with
     the masthead. Padding only, not font-size, respects that. */
  padding: 4px 8px;
  font-family: var(--font-body);
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
  min-width: 28px;
  line-height: 1;
}
.fz-selector__btn:hover {
  background: var(--paper-2);
  border-color: var(--rule);
}
.fz-selector__btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
.fz-selector__btn--active {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.fz-selector__btn[data-fz="sm"] { font-size: 0.78rem; }
.fz-selector__btn[data-fz="md"] { font-size: 0.92rem; }
.fz-selector__btn[data-fz="lg"] { font-size: 1.05rem; }

@media (max-width: 540px) {
  .fz-selector {
    /* Tighter on phones; the label hides to save room. */
    padding: 2px 6px;
  }
  .fz-selector__label { display: none; }
}

/* Three text-size scales — applied at the :root level so every
   var(--text-*) downstream rescales proportionally. The default
   (.fz--md) matches the prior baseline so existing pages render
   identically until the user picks small or large. */
html.fz--sm {
  --text-xs:   0.7rem;
  --text-sm:   0.8rem;
  --text-base: 0.875rem;
  --text-md:   1.05rem;
  --text-lg:   1.3rem;
  --text-xl:   1.6rem;
}
html.fz--md {
  /* default — keep current values */
}
html.fz--lg {
  --text-xs:   1.05rem;
  --text-sm:   1.2rem;
  --text-base: 1.45rem;
  --text-md:   1.8rem;
  --text-lg:   2.25rem;
  --text-xl:   2.85rem;
}
html.fz--lg body { line-height: 1.7; }
html.fz--lg .post-headline { font-size: clamp(1.6rem, 2vw + 0.8rem, 2.2rem) !important; }

/* ---- AAA contrast sweep — colored dim elements (eve 2026-05-02) -----
   Force readable foreground on every text element that lives inside a
   colored dimension surface, regardless of cascade specificity.
   Operator complaint: "you fixed contrast on pills but not on the
   colored dimension bars next to the expanders". This block uses
   !important to win over earlier rules and applies to:
     - summary.dimension__head colored bar (RED/ORANGE/MAROON/GREEN/NAVY/CHARCOAL)
     - .briefing-section--* tinted background panels
     - .dimension__narrative (per-dim narrative box)
     - all child text + svg + the count/cue/chevron
*/
.dimension-block > .dimension > summary.dimension__head,
.dimension-block > .dimension > summary.dimension__head h1,
.dimension-block > .dimension > summary.dimension__head h2,
.dimension-block > .dimension > summary.dimension__head h3,
.dimension-block > .dimension > summary.dimension__head h4,
.dimension-block > .dimension > summary.dimension__head p,
.dimension-block > .dimension > summary.dimension__head span,
.dimension-block > .dimension > summary.dimension__head a,
.dimension-block > .dimension > summary.dimension__head svg {
  color: var(--paper) !important;
  fill: currentColor !important;
}
.dimension-block > .dimension > summary.dimension__head .dimension__count,
.dimension-block > .dimension > summary.dimension__head .dimension__expand,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue--open,
.dimension-block > .dimension > summary.dimension__head .dimension__expand-cue--closed {
  color: var(--paper) !important;
  opacity: 1 !important;
}
.dimension-block > .dimension > summary.dimension__head .dimension__expand-chevron {
  stroke: var(--paper) !important;
  color: var(--paper) !important;
}

/* Dim narrative panel — tinted background with colored border. Force
   the prose + blog-link to use --ink (dark) for AAA on the tints. */
.dimension-block .dimension__narrative {
  color: var(--ink);
}
.dimension-block .dimension__narrative-prose {
  color: var(--ink) !important;
  font-size: var(--text-base);
  line-height: 1.65;
}
.dimension-block .dimension__narrative-blog-link {
  color: var(--navy) !important;
  font-weight: 700;
}
.dimension-block .dimension__narrative-blog-link:hover {
  color: var(--ink) !important;
}

/* briefing-section colored panels — kicker color tuned for AAA on
   the matching tinted background. Existing color variables are AAA
   on white, but the kicker sits on var(--*-bg) (very light tint of
   same hue) which has slightly lower contrast. Use the deeper
   variant for kicker text. */
/* Operator 2026-05-04 canonical palette — these used to override the
   earlier per-dim rules with old `var(--*)` values; now they use the
   exact same hex codes as the pills + dim heads + blog so pills,
   dim band, kickers, mentions, narrative-icon all read as one color
   per dim. */
.briefing-section--under-emergency-order .briefing-section__kicker { color: #dc2626 !important; }
.briefing-section--recent-failures .briefing-section__kicker        { color: #F97316 !important; }
.briefing-section--worst-offenders .briefing-section__kicker,
.briefing-section--bad-actors .briefing-section__kicker             { color: #8B1818 !important; }
.briefing-section--worsts .briefing-section__kicker                 { color: #ff5722 !important; }
.briefing-section--permanent-closures .briefing-section__kicker,
.briefing-section--closures .briefing-section__kicker               { color: #6B5B4E !important; }
.briefing-section--most-improved .briefing-section__kicker,
.briefing-section--clean-plates .briefing-section__kicker           { color: #16a34a !important; }
.briefing-section--openings .briefing-section__kicker,
.briefing-section--new-licenses .briefing-section__kicker           { color: #06b6d4 !important; }
.briefing-section--ghost-licenses .briefing-section__kicker         { color: #64748b !important; }
.briefing-section--lost-licenses .briefing-section__kicker          { color: #1A3D6D !important; }
.briefing-section--chain-activity .briefing-section__kicker         { color: #9333ea !important; }

/* ---- Briefing mentions — section-color consistency -------------------
   Operator 2026-05-02: alternating mention colors must have a clear
   purpose. Each mention's color now matches the SECTION it appears
   in (not the mention's own kind), so within a single dim-narrative
   paragraph all mentions share one color = "this is where these
   restaurants live on the page". Confirmation tier still shows via
   icon (Google G / Foursquare / Facebook) and underline weight.
*/
/* Operator 2026-05-04 canonical palette for briefing-mentions —
   per-dim hex codes from config/dimensions.json. */
.briefing-section--under-emergency-order .briefing-mention,
.briefing-section--under-emergency-order .briefing-mention[data-kind] {
  color: #dc2626 !important;
  border-bottom-color: #dc2626 !important;
}
.briefing-section--recent-failures .briefing-mention,
.briefing-section--recent-failures .briefing-mention[data-kind] {
  color: #F97316 !important;
  border-bottom-color: #F97316 !important;
}
.briefing-section--worst-offenders .briefing-mention,
.briefing-section--worst-offenders .briefing-mention[data-kind],
.briefing-section--bad-actors .briefing-mention,
.briefing-section--bad-actors .briefing-mention[data-kind] {
  color: #8B1818 !important;
  border-bottom-color: #8B1818 !important;
}
.briefing-section--worsts .briefing-mention,
.briefing-section--worsts .briefing-mention[data-kind] {
  color: #ff5722 !important;
  border-bottom-color: #ff5722 !important;
}
.briefing-section--permanent-closures .briefing-mention,
.briefing-section--permanent-closures .briefing-mention[data-kind],
.briefing-section--closures .briefing-mention,
.briefing-section--closures .briefing-mention[data-kind] {
  color: #6B5B4E !important;
  border-bottom-color: #6B5B4E !important;
}
.briefing-section--most-improved .briefing-mention,
.briefing-section--most-improved .briefing-mention[data-kind],
.briefing-section--clean-plates .briefing-mention,
.briefing-section--clean-plates .briefing-mention[data-kind] {
  color: #16a34a !important;
  border-bottom-color: #16a34a !important;
}
.briefing-section--openings .briefing-mention,
.briefing-section--openings .briefing-mention[data-kind],
.briefing-section--new-licenses .briefing-mention,
.briefing-section--new-licenses .briefing-mention[data-kind] {
  color: #06b6d4 !important;
  border-bottom-color: #06b6d4 !important;
}
.briefing-section--ghost-licenses .briefing-mention,
.briefing-section--ghost-licenses .briefing-mention[data-kind] {
  color: #64748b !important;
  border-bottom-color: #64748b !important;
}
.briefing-section--lost-licenses .briefing-mention,
.briefing-section--lost-licenses .briefing-mention[data-kind] {
  color: #1A3D6D !important;
  border-bottom-color: #1A3D6D !important;
}
.briefing-section--chain-activity .briefing-mention,
.briefing-section--chain-activity .briefing-mention[data-kind] {
  color: #9333ea !important;
  border-bottom-color: #9333ea !important;
}

/* The same applies to the dimension narrative panels at the top of
   each dim block (briefing prose lives in two places: the per-section
   briefing-section--* boxes AND the dim narratives directly under
   each colored summary bar). Same purpose: color = which section. */
/* Operator 2026-05-04 canonical palette for narrative-block mentions */
.dimension-block[data-dim="under-emergency-order"] .briefing-mention {
  color: #dc2626 !important; border-bottom-color: #dc2626 !important;
}
.dimension-block[data-dim="recent-failures"] .briefing-mention {
  color: #F97316 !important; border-bottom-color: #F97316 !important;
}
.dimension-block[data-dim="worst-offenders"] .briefing-mention,
.dimension-block[data-dim="bad-actors"] .briefing-mention {
  color: #8B1818 !important; border-bottom-color: #8B1818 !important;
}
.dimension-block[data-dim="worsts"] .briefing-mention {
  color: #ff5722 !important; border-bottom-color: #ff5722 !important;
}
.dimension-block[data-dim="permanent-closures"] .briefing-mention,
.dimension-block[data-dim="closures"] .briefing-mention {
  color: #6B5B4E !important; border-bottom-color: #6B5B4E !important;
}
.dimension-block[data-dim="most-improved"] .briefing-mention,
.dimension-block[data-dim="clean-plates"] .briefing-mention {
  color: #16a34a !important; border-bottom-color: #16a34a !important;
}
.dimension-block[data-dim="openings"] .briefing-mention,
.dimension-block[data-dim="new-licenses"] .briefing-mention {
  color: #06b6d4 !important; border-bottom-color: #06b6d4 !important;
}
.dimension-block[data-dim="ghost-licenses"] .briefing-mention {
  color: #64748b !important; border-bottom-color: #64748b !important;
}
.dimension-block[data-dim="lost-licenses"] .briefing-mention {
  color: #1A3D6D !important; border-bottom-color: #1A3D6D !important;
}
.dimension-block[data-dim="chain-activity"] .briefing-mention {
  color: #9333ea !important; border-bottom-color: #9333ea !important;
}

/* ---- Briefing-mention single-color enforcement ---------------------
   The wrapMentions output is <a class="briefing-mention"><strong
   class="mention">NAME</strong>...</a>. Both elements have their
   own color rules and end up rendering the strong text in --ink while
   the anchor underline is the section color — visually a TWO-color
   restaurant name. Force the inner strong / mention text to inherit
   the anchor color so each mention reads as ONE consistent color.
*/
.briefing-mention,
.briefing-mention .mention,
.briefing-mention strong,
.briefing-mention strong.mention {
  color: inherit !important;
}
.briefing-mention .briefing-mention__check,
.briefing-mention .briefing-mention__source-icon {
  color: inherit !important;
  fill: currentColor;
}

/* ---- Dimension expander redesign (eve 2026-05-02) ---------------
   The "Show N records" button must read as a clear button on the
   colored bar — undo the white-text inheritance ONLY for this
   specific control, give it paper bg + ink text + crisp border.
   Heading allowed to wrap to 2 lines max on mobile.
*/
.dimension-block > .dimension > summary.dimension__head .dimension__expand {
  background: var(--paper) !important;
  color: var(--ink) !important;
  border: 1px solid var(--paper) !important;
  border-radius: 999px !important;
  padding: 4px 12px !important;
  font-size: var(--text-xs) !important;
  font-weight: 700 !important;
  letter-spacing: 0.02em !important;
  flex: 0 0 auto;
  white-space: nowrap;
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
}
.dimension-block > .dimension > summary.dimension__head:hover .dimension__expand {
  background: var(--paper-2) !important;
  border-color: var(--paper-2) !important;
}
.dimension-block > .dimension > summary.dimension__head .dimension__expand .dimension__expand-cue,
.dimension-block > .dimension > summary.dimension__head .dimension__expand .dimension__expand-cue--open,
.dimension-block > .dimension > summary.dimension__head .dimension__expand .dimension__expand-cue--closed {
  color: var(--ink) !important;
  opacity: 1 !important;
}
.dimension-block > .dimension > summary.dimension__head .dimension__expand .dimension__expand-chevron {
  stroke: var(--ink) !important;
  color: var(--ink) !important;
}

/* Tighter bar overall. */
.dimension-block > .dimension > summary.dimension__head {
  padding: 8px 12px;
  margin: 0 0 var(--s-3);
  gap: var(--s-2);
  align-items: center;
}
.dimension-block > .dimension > summary.dimension__head .dimension__heading {
  font-size: var(--text-base);
  line-height: 1.25;
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

/* Mobile: cap heading to 2 lines so verbose subtitles don't bloat
   the bar (e.g. "Near miss — high violations, NOT closed"). */
@media (max-width: 640px) {
  .dimension-block > .dimension > summary.dimension__head {
    min-height: 44px;
    padding: 6px 10px;
    align-items: center;
  }
  .dimension-block > .dimension > summary.dimension__head .dimension__heading {
    font-size: var(--text-sm);
    line-height: 1.2;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .dimension-block > .dimension > summary.dimension__head .dimension__expand {
    min-height: 32px;
    padding: 5px 10px !important;
    font-size: 0.72rem !important;
  }
}

/* Final UX/a11y pass: all phone-reachable controls meet the 44px
   target floor, while search empty-state copy has a visible panel. */
@supports (height: 100dvh) {
  body { min-height: 100dvh; }
}

.metro-search__empty-panel[hidden] { display: none !important; }

@media (max-width: 640px), (pointer: coarse) {
  /* Tap-target floor — min-height only. min-width on the jump-nav
     pills was making them render as 44x44 circles (with their 999px
     border-radius). Pills already grow horizontally to fit their
     label; let them. */
  .fz-selector__btn,
  .riskyeats-toolbar .a2a_kit > a,
  .riskyeats-toolbar__follow .follow-link,
  .footer-legal > summary {
    min-width: 44px;
    min-height: 44px;
  }
  .metro-chip,
  .jump-nav__link,
  .card__link,
  .sunbiz-link,
  .more-cards__btn {
    min-height: 44px;
  }
  .fz-selector__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding-inline: 10px;
  }
  .card__actions {
    gap: 8px;
  }
  .card__link,
  .sunbiz-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .contrib-banner:hover,
  .card--search-hit,
  .provider-logo:hover {
    transform: none !important;
  }
}

/* ---- Card whitespace tightening (eve 2026-05-02) ---------------------
   Operator: 'fix card whitespace'. Cards were s-3 padding + s-2 row-gap
   = ~28px vertical breathing room around each child. Drop to s-2 / s-1
   so the same content reads tighter. Touched: .card padding+gap,
   .card__head gap, .card__stats gap, .card__violations margin,
   .card__actions margin, .card__location margin.
*/
.card {
  padding: var(--s-2) var(--s-3) !important;
  row-gap: var(--s-1) !important;
  column-gap: var(--s-2) !important;
}
.card__head {
  gap: 1px !important;
  margin: 0 !important;
}
.card__name {
  margin: 0 !important;
  line-height: 1.2 !important;
}
.card__location {
  margin: 0 !important;
  line-height: 1.3 !important;
}
.card__violations,
.card__violations-row {
  margin: 2px 0 !important;
}
.card__stats {
  margin: 0 !important;
  gap: var(--s-2) !important;
  padding: 0 !important;
}
.card__stat {
  margin: 0 !important;
  padding: 0 !important;
}
.card__stat dt {
  margin: 0 !important;
  line-height: 1.1 !important;
}
.card__stat dd {
  margin: 0 !important;
  line-height: 1.1 !important;
}
.card__actions {
  margin: var(--s-1) 0 0 !important;
  padding: 0 !important;
  gap: var(--s-2) !important;
}
.card__counts,
.card__disposition {
  margin: 0 !important;
  line-height: 1.3 !important;
}
.card__meta {
  gap: var(--s-1) !important;
  margin: 0 !important;
}
@media (max-width: 540px) {
  .card {
    padding: var(--s-2) !important;
    row-gap: 4px !important;
  }
}

/* ---- Pill height clamp — masthead can't stretch beyond pill-h --------
   Codex's a11y pass introduced unexpected vertical stretching on the
   four masthead pills (homepage screenshot showed them as 300px-tall
   ovals on widescreen). Cap height at 44px max so they always read
   as compact pill rows. */
.metro-picker__select-wrap,
.metro-picker__search-wrap .metro-search,
.metro-picker__blog-cta,
.metro-picker__signup-form {
  max-height: 44px !important;
  height: var(--pill-h, 38px) !important;
  align-items: center !important;
}

/* (Old single-row scoreboard removed; replaced with 2x5 modular grid below.) */

/* ---- Stat-band — GRAEAE 2x5 modular grid (eve 2026-05-03) -------
   Print-newspaper aesthetic: consistent card heights, bold uppercase
   labels above subdued numeric values, 6px colored left border per
   bucket, subtle tinted backgrounds. 9 stats in 2 rows × 5 cols
   (one slot for the metro heading) on wide desktop; 3 cols on
   tablet; stacked list on mobile.
*/

/* Tablet — 3-col grid */
@media (min-width: 641px) and (max-width: 1023px) {
  .stat-band {
    display: block !important;
    padding: var(--badge-pad-y) var(--badge-pad-x) !important;
    background: var(--paper-2) !important;
    border: 1px solid var(--rule) !important;
    border-radius: var(--badge-radius-tag) !important;
    max-width: var(--measure-grid) !important;
    margin: 0 auto !important;
    text-align: center !important;
  }
  .stat-band .stat-grid {
    display: grid !important;
    grid-template-columns: repeat(3, 1fr) !important;
    gap: var(--s-2) !important;
    margin: 0 auto !important;
  }
  .stat-band__heading,
  .stat-band__metro { display: block !important; grid-column: 1 / -1; }
  .stat-band__heading {
    font-size: var(--badge-font);
    font-family: var(--font-body);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--ink-muted);
    text-align: center;
    margin: 0 0 var(--s-2);
  }
  .stat-band__metro {
    color: var(--red-deep);
    font-weight: 700;
  }
}

/* Wide desktop — 2x5 modular grid (operator + GRAEAE 2026-05-03) */
@media (min-width: 1024px) {
  .stat-band {
    display: block !important;
    padding: var(--badge-pad-y) var(--badge-pad-x) !important;
    background: var(--paper-2) !important;
    border: 1px solid var(--rule) !important;
    border-radius: var(--badge-radius-tag) !important;
    max-width: var(--measure-grid) !important;
    margin: 0 auto !important;
    text-align: center !important;
  }
  .stat-band .stat-grid {
    display: grid !important;
    grid-template-columns: repeat(5, 1fr) !important;
    grid-auto-rows: minmax(64px, auto) !important;
    gap: var(--s-2) !important;
    align-items: stretch !important;
    margin: 0 auto !important;
  }
  .stat-band__heading {
    display: block !important;
    text-align: center;
    font-family: var(--font-body);
    font-size: var(--badge-font);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--ink-muted);
    text-align: center;
    margin: 0 0 var(--s-2);
  }
  .stat-band__metro {
    display: inline !important;
    color: var(--red-deep);
    font-weight: 800;
  }
}

/* Stat tile shared geometry (tablet + desktop) */
@media (min-width: 641px) {
  .stat-tile {
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
    align-items: flex-start !important;
    gap: 4px !important;
    height: auto !important;
    min-height: 64px !important;
    padding: 8px 10px 8px 14px !important;
    border: 1px solid var(--rule) !important;
    border-left: 6px solid var(--accent, var(--ink-muted)) !important;
    border-radius: 4px !important;
    background: var(--paper) !important;
    margin: 0 !important;
  }
  .stat-tile__label {
    font-family: var(--font-body) !important;
    font-size: 0.72rem !important;
    font-weight: 700 !important;
    text-transform: uppercase !important;
    letter-spacing: 0.06em !important;
    color: var(--ink-muted) !important;
    line-height: 1.2 !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    max-width: 100%;
  }
  .stat-tile__value {
    font-family: var(--font-display) !important;
    font-variation-settings: "opsz" 48 !important;
    font-size: 1.6rem !important;
    font-weight: 700 !important;
    line-height: 1.05 !important;
    color: var(--ink) !important;
    font-variant-numeric: tabular-nums !important;
  }
  /* Bucket palette per stat */
  .stat-tile--under-emergency-order {
    border-left-color: #dc2626 !important;
    background: rgba(161, 21, 21, 0.04) !important;
  }
  .stat-tile--recent-failures {
    border-left-color: #F97316 !important;
    background: rgba(154, 52, 18, 0.05) !important;
  }
  .stat-tile--worst-offenders,
  .stat-tile--bad-actors {
    border-left-color: #8B1818 !important;
    background: rgba(107, 15, 15, 0.04) !important;
  }
  .stat-tile--clean-plates,
  .stat-tile--most-improved {
    border-left-color: #16a34a !important;
    background: rgba(31, 93, 45, 0.05) !important;
  }
  .stat-tile--openings,
  .stat-tile--new-licenses {
    border-left-color: #06b6d4 !important;
    background: rgba(6, 182, 212, 0.05) !important;
  }
  .stat-tile--lost-licenses {
    border-left-color: #1A3D6D !important;
    background: rgba(26, 61, 109, 0.05) !important;
  }
  .stat-tile--permanent-closures {
    border-left-color: #6B5B4E !important;
    background: rgba(153, 27, 27, 0.04) !important;
  }
}

/* ---- Today on the Blog feature (homepage) ----------------------------
   Prominent hero strip below stat-band, above briefing prose.
   Operator 2026-05-03: blog needed to feel more important on main page.
*/
.todays-blog {
  /* NO max-width, and no auto side margins. This is a CHILD of
     .metro-briefing, already capped at var(--measure-grid) --
     `min(1280px, 100% - 2 * var(--s-4))`. On a child the `100%` resolves
     against the parent's already-capped content box, so re-declaring it
     subtracted the gutter TWICE and left this box about two gutters narrower
     than the dimension cards below it at every width. `margin: ... auto` then
     centred that narrower box, which is what read as "not reflowing". */
  align-self: stretch;
  justify-self: stretch;
  width: 100%;
  box-sizing: border-box;
  margin: var(--s-5) 0;
  padding: var(--s-4);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 8px;
  border-top: 6px solid var(--red);
}
.todays-blog__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-3);
  flex-wrap: wrap;
}
.todays-blog__avatar {
  /* 64px -> 80px, same operator note. The head band is a flex row with
     ``flex-wrap`` and the text beside it is ``flex: 1 1 200px``, so the extra
     16px comes out of the text column rather than forcing a wrap. */
  width: 80px;
  height: 80px;
  border-radius: 50%;
  border: 3px solid var(--paper);
  box-shadow: 0 0 0 1px var(--rule);
  object-fit: cover;
  object-position: center top;
  flex-shrink: 0;
}
.todays-blog__head-text {
  flex: 1 1 200px;
  min-width: 0;
}
.todays-blog__kicker {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  margin: 0 0 var(--s-1);
}
.todays-blog__title {
  font-family: var(--font-display);
  font-variation-settings: "opsz" 48;
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.2;
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}
.todays-blog__thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--s-3);
  margin: var(--s-3) 0;
}
.todays-blog__thumb {
  display: block;
  position: relative;
  border-radius: 6px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--rule);
  background: var(--paper-3, #ECECEC);
  transition: transform 120ms ease;
}
.todays-blog__thumb:hover {
  transform: translateY(-2px);
}
.todays-blog__thumb img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
}
.todays-blog__thumb-label {
  display: block;
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  color: #FFFFFF;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,0.65));
  text-shadow: 0 1px 4px rgba(0,0,0,0.7);
}
/* Mobile single-hero — hidden on desktop / iPad, shown only on
   narrow viewports (operator 2026-05-03: mobile = too much scroll
   with 3 thumbnails, collapse to 1 selected-metro hero). */
.todays-blog__hero--mobile {
  display: none;
}
.todays-blog__hero {
  position: relative;
  border-radius: 6px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  border: 1px solid var(--rule);
  background: var(--paper-3, #ECECEC);
  transition: transform 120ms ease;
}
.todays-blog__hero:hover {
  transform: translateY(-2px);
}
.todays-blog__hero img {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
}
.todays-blog__hero-label {
  display: block;
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  color: #FFFFFF;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,0.65));
  text-shadow: 0 1px 4px rgba(0,0,0,0.7);
}
.todays-blog__cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  align-items: center;
  justify-content: space-between;
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--rule);
}
.todays-blog__cta {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--paper);
  background: var(--red);
  border: 1px solid var(--red);
  border-radius: 999px;
  padding: 8px 18px;
  text-decoration: none;
}
.todays-blog__cta:hover {
  background: var(--red-deep);
  border-color: var(--red-deep);
}
.todays-blog__contrib {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--navy);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.todays-blog__contrib:hover {
  color: var(--ink);
}
@media (max-width: 768px) {
  /* Hide the 3-thumbnail grid on mobile, show the single selected-
     metro hero in its place. Operator 2026-05-03: mobile scroll budget
     does not allow 3 hero images stacked. */
  .todays-blog__thumbs {
    display: none;
  }
  .todays-blog__hero--mobile {
    display: block;
    margin: var(--s-3) 0;
  }
  .todays-blog {
    padding: var(--s-3);
    margin: var(--s-3) auto;
  }
  .todays-blog__title {
    font-size: var(--text-base);
  }
  .todays-blog__hero-label,
  .todays-blog__thumb-label {
    font-size: var(--text-xs);
  }
  .todays-blog__cta-row {
    flex-direction: column;
    align-items: stretch;
  }
  .todays-blog__cta {
    text-align: center;
  }
}

/* ---- Find-a-Resto: explicit clear + match chips (2026-05-03) -------
   Per Stuart Skolnik beta feedback: HTML5 input[type=search] X is
   missing on iOS/older mobiles, and a 1-match result was invisible
   without auto-scroll. Add explicit Clear button + a chip list of
   matches that the reader can click without scrolling.
*/
.metro-search__clear {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  height: 32px;
  margin-left: 0;
  padding: 0 12px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
}
.metro-search__clear:hover,
.metro-search__clear:focus-visible {
  background: var(--paper-2);
  outline: none;
  border-color: var(--ink);
}
.metro-search__matches {
  flex: 1 0 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin-top: var(--s-1);
}
.metro-search__matches[hidden] {
  display: none;
}
.metro-search__match-chip {
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 600;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  background: var(--paper-2);
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: var(--badge-radius-pill);
  cursor: pointer;
  text-align: left;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background 120ms ease, border-color 120ms ease;
}
.metro-search__match-chip:hover,
.metro-search__match-chip:focus-visible {
  background: var(--red);
  color: var(--paper);
  border-color: var(--red);
  outline: none;
}
@media (max-width: 640px) {
  .metro-search__match-chip {
    font-size: var(--badge-font);
    padding: var(--badge-pad-y) var(--badge-pad-x);
  }
}

/* ---- Incremental card row ---------------------------------------- */
.more-cards__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-2);
  align-items: center;
}
/* Auto-paging (IntersectionObserver present): cards arrive as the reader
   scrolls, so "Show next N" has nothing left to do and is withdrawn. The
   class is added by JS only -- when the observer is unavailable the row
   never gets it and the explicit next-page button remains as the fallback.
   The full-metro Search link remains visible in both modes. The sentinel must
   stay in flow with real height -- a zero-height
   or display:none element is never intersected, so auto-paging would
   simply never fire. */
.more-cards__row--auto button.more-cards__btn {
  display: none;
}
.more-cards__progress {
  margin: 0;
  color: var(--ink-muted);
  font-size: var(--meta-font);
  font-variant-numeric: tabular-nums;
}
.more-cards__sentinel {
  height: 1px;
  margin: 0;
  padding: 0;
}
.more-cards__btn--all {
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule);
}
.more-cards__btn--all:hover,
.more-cards__btn--all:focus-visible {
  background: var(--paper-2);
  border-color: var(--ink);
  color: var(--ink);
  outline: none;
}
@media (max-width: 640px) {
  .more-cards__row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-1);
  }
  .more-cards__row .more-cards__btn {
    width: 100%;
    text-align: center;
  }
}

/* ---- Device tier transparency (2026-05-03) ----------------------
   Per Stuart Skolnik feedback + operator: when the user hits the
   'Show next 10' restriction, surface WHY — what tier did we detect.
   Tiny calm pill near the search; per-row caption alongside the
   Show-next/Show-all buttons.
*/
.device-tier-badge {
  flex: 1 0 100%;
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  margin-top: var(--s-1);
  padding: var(--badge-pad-y) var(--badge-pad-x);
  font-family: var(--font-body);
  font-size: var(--badge-font);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-muted, #6B6B6B);
  background: var(--paper-2, #F4F1E8);
  border: 1px solid var(--rule);
  border-radius: var(--badge-radius-pill);
  width: fit-content;
  cursor: help;
  user-select: none;
}
.device-tier-badge::before {
  content: "Device:";
  margin-right: 0.18rem;
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--badge-font);
  letter-spacing: 0.05em;
  color: var(--ink);
}
.device-tier-badge--ram-2g {
  border-color: rgba(180, 60, 40, 0.45);
  background: rgba(255, 200, 100, 0.22);
}
.device-tier-badge--ram-4g {
  border-color: rgba(150, 100, 40, 0.40);
  background: rgba(255, 220, 130, 0.18);
}
.device-tier-badge--ram-6g {
  border-color: rgba(0, 0, 0, 0.10);
  background: rgba(220, 220, 220, 0.20);
}
.device-tier-badge--ram-8g {
  border-color: rgba(43, 132, 65, 0.45);
  background: rgba(43, 132, 65, 0.10);
}
.device-tier-badge--desktop {
  border-color: rgba(43, 87, 132, 0.45);
  background: rgba(43, 87, 132, 0.10);
}
/* Legacy tier names retained for any cached HTML still in flight. */
.device-tier-badge--low,
.device-tier-badge--mid,
.device-tier-badge--high {
  border-color: rgba(0, 0, 0, 0.10);
  background: rgba(220, 220, 220, 0.20);
}
.more-cards__caption {
  font-family: var(--font-body);
  font-size: 0.72rem;
  color: var(--ink-muted, #6B6B6B);
  align-self: center;
  margin-left: var(--s-1);
}
@media (max-width: 640px) {
  .device-tier-badge {
    font-size: var(--badge-font);
    padding: var(--badge-pad-y) var(--badge-pad-x);
  }
  .more-cards__caption {
    flex: 1 0 100%;
    text-align: center;
    margin-left: 0;
    margin-top: 0.32rem;
  }
}

/* ---- Find-a-Resto status text wrap (Laura @ Amazon, 2026-05-03) ---
   Long status strings ('Showing N matches. First X below — click to
   jump...') were clipping mid-sentence on narrower viewports. Force
   wrap behaviour so the entire status reads inside its box.
*/
.metro-search__status,
.metro-search__matches {
  white-space: normal;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.metro-search__status {
  line-height: 1.45;
  padding: 0.2rem 0.1rem;
}

/* ---- Masthead auto-hide on scroll (2026-05-03) ------------------
   Operator: 'header eats a ton of space; during scroll, we auto
   hide.' Classic news-app pattern. JS in index.html toggles the
   --hidden class based on scroll direction. Within first 100px
   we keep it pinned for orientation.
*/
.metro-picker {
  transition: transform 220ms ease;
  will-change: transform;
}
.metro-picker--hidden {
  transform: translateY(-105%);
}
@media (prefers-reduced-motion: reduce) {
  .metro-picker { transition: none; }
}

/* ---- Condensed footer (2026-05-03) ----------------------------
   Operator: 'too big'. Data sources moved to disclosure.html;
   footer is now a single line.
*/
.footer-compact {
  font-family: var(--font-body);
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-muted, #6B6B6B);
  text-align: center;
  margin: 0;
  padding: var(--s-2) var(--s-3);
}
.footer-compact a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  margin: 0 0.1rem;
}
.footer-compact a:hover { color: var(--red); }
.footer-meta {
  font-size: 0.75rem;
  opacity: 0.75;
}

/* ---- Card width + violation wrap ---------------------------------
   Cards now use one full-width reading flow rather than the retired desktop
   card grid. Keep child content from widening the feed, but do not clip the
   card itself: an evidence row or focus outline must be allowed to finish its
   natural geometry. */
.card {
  min-width: 0;
}
.card__details,
.card__details[open] {
  max-width: 100%;
  overflow: hidden;
}
.violations {
  max-width: 100%;
  overflow: hidden;
}
.violation {
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}
.violation__label,
.violation__snippet {
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
  white-space: normal;
}
.violation__snippet {
  hyphens: auto;
}
.violation__code {
  flex-shrink: 0;
}
/* Right-rail dimension badge — abbreviate on narrow cards rather than truncate. */
.card__section {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.dimension-badge.card__section {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
@media (max-width: 1023px) {
  /* Mobile / 1-col stacks have plenty of horizontal room — full label. */
  .card__section { max-width: none; }
}
@media (min-width: 1024px) {
  /* On the 3-col / 4-col desktop card stack, keep long labels inside
     the narrow meta rail without clipping to a fragment. */
  .card-stack .card__section {
    font-size: 10px;
    padding: 1px 6px;
    letter-spacing: 0;
  }
}

/* ---- Card stack alignment fix (2026-05-03 PC screenshot) ----
   Stuart's PC view: when one card has 'All violations' expanded the
   sibling cards stretched to equal height leaving huge whitespace.
   Align children to the top instead.

   Also loosen the previous overflow-wrap: anywhere which was breaking
   mid-word ('Single-service / articles' looked broken). break-word
   only splits when a single token won't fit, never inside a normal
   word.
*/
.card-stack {
  align-items: start;
}
.violation,
.violation__label,
.violation__snippet {
  overflow-wrap: break-word;
  word-break: normal;
  hyphens: manual;
}

/* Inspection is already its own card face, so "All violations" is a compact
   visible receipt—not a second disclosure. Keep each priority tag and its
   text together in a dense two-column line, and let long DBPR snippets wrap
   beneath the text column instead of producing a tall, staggered list. */
.card__details--violations {
  margin-top: var(--s-2);
  padding-top: 0;
}
.card__details--violations .card__violations-title {
  margin: 0 0 6px;
  padding: 0;
}
.card__details--violations .violations { gap: 6px; }
.card__details--violations .violation {
  grid-template-columns: 3.5em minmax(0, 1fr);
  gap: 4px 8px;
  align-items: start;
}
.card__details--violations .violation__label {
  font-size: var(--text-sm);
  line-height: 1.28;
}
.card__details--violations .violation__snippet {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.3;
}

/* ==== Codex desktop UX recommendations (2026-05-03) ============ */

/* HIGH #2 — search status / matches break out of the fixed-height
   pill on desktop. Render them as positioned children that flow
   below the search pill rather than inside it. */
@media (min-width: 1024px) {
  .metro-picker__search-wrap .metro-search {
    position: relative;
  }
  .metro-search__status,
  .metro-search__matches {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 2px);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 6px;
    padding: 0.4rem 0.7rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    z-index: 50;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--ink);
  }
  .metro-search__status:empty {
    display: none;
  }
  .metro-search__matches[hidden] {
    display: none;
  }
}

/* HIGH #3 — when 'All violations' (or any card details) is open,
   let it span the full card width so violations don't get squeezed
   into the narrow body column on a 3-col desktop grid. */
.card__details[open] {
  grid-column: 1 / -1;
  margin-top: var(--s-2);
}

/* HIGH #4 — desktop masthead too tall. Move share/follow strip into
   footer (HTML moved separately). On the masthead, hide it. */
@media (min-width: 1024px) {
  .metro-picker__social--top,
  .metro-picker__social {
    display: none !important;
  }
}

/* MED #6 — jump-nav: widen max-width on desktop + single-row
   horizontally scrollable for the narrow-desktop case. */
@media (min-width: 1024px) {
  .jump-nav {
    flex-wrap: nowrap !important;
    overflow-x: auto !important;
    max-width: min(1400px, 100% - 2 * var(--s-4)) !important;
    scrollbar-width: thin;
  }
}

/* MED #8 — signup status renders below the form pill on desktop,
   matching the search status pattern. */
@media (min-width: 1024px) {
  .metro-picker__signup-form {
    position: relative;
  }
  .metro-picker__signup-status:not(:empty) {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 2px);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 6px;
    padding: 0.4rem 0.7rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    z-index: 50;
    font-size: 0.82rem;
    line-height: 1.45;
    color: var(--ink);
  }
}

/* MED #10 — text-size pill (.fz-selector) tightened on desktop so
   it's a smaller cluster, less competing-with-masthead. */
@media (min-width: 1024px) {
  .fz-selector {
    transform: scale(0.85);
    transform-origin: top right;
  }
}

/* LOW #11 — 'Tap' vs 'Click' wording per pointer type. Replaces the
   visible 'Tap' text inside .worst-today__sub on devices with a fine
   pointer (mouse/trackpad). */
@media (pointer: fine) {
  .worst-today__sub .pointer-tap {
    display: none;
  }
  .worst-today__sub .pointer-click {
    display: inline;
  }
}
@media (pointer: coarse), (pointer: none) {
  .worst-today__sub .pointer-click {
    display: none;
  }
  .worst-today__sub .pointer-tap {
    display: inline;
  }
}

/* LOW #12 — footer bumped slightly larger + higher contrast for a
   public-records site that wants its credit + freshness readable. */
.footer-compact {
  font-size: 0.9rem;
  color: var(--ink);
}
.footer-meta {
  font-size: 0.82rem;
  opacity: 0.85;
}
.footer-compact a {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---- Persona attribution UI (operator 2026-05-03) ----------------- */
/* Per-dim narrative voice avatar — small portrait of the correspondent
   who voiced THAT paragraph. Important for keys-pair (Florida Keys)
   where Clancy and Gracie alternate by dim; cosmetic but reinforcing
   for single-persona metros. */
.dimension__narrative {
  position: relative;
}
.dimension__narrative-voice {
  /* 40px -> 56px -> 72px (operator 2026-08-17, second pass: still too small
     after the first bump). Floated with shape-outside, so the prose wrap
     follows the new radius automatically and the ::after clearfix below
     still handles paragraphs shorter than the portrait. */
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 2px solid var(--ink);
  object-fit: cover;
  /* Operator 2026-05-03: float so prose wraps around the avatar
     instead of stacking with vertical whitespace. Side margins +
     small bottom margin keep clean wrap. */
  float: left;
  margin: 0 10px 4px 0;
  shape-outside: circle(50%);
  background: #fff;
}
.dimension__narrative-body::after {
  content: "";
  display: block;
  clear: both;
}
[data-voice="inspector-clancy"] .dimension__narrative-voice {
  border-color: #0d9488;
}
[data-voice="mama-gracie"] .dimension__narrative-voice {
  border-color: #9d174d;
}

/* Today-on-the-Blog dual-portrait pair (keys-pair correspondents). */
.todays-blog__avatar-pair {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  gap: 8px;
}
.todays-blog__avatar-pair .todays-blog__avatar {
  border: 3px solid var(--ink);
  border-radius: 50%;
  background: #fff;
  /* Kept in step with the single portrait above: the pair renders in the same
     head band, and two different diameters in one row reads as a mistake. */
  width: 80px;
  height: 80px;
  object-fit: cover;
  position: static;  /* override any earlier absolute positioning */
}
@media (max-width: 480px) {
  .todays-blog__avatar-pair .todays-blog__avatar {
    /* 52px -> 64px. Two portraits plus an 8px gap still fit a 320px viewport
       (64+64+8 = 136px), leaving the byline its column. */
    width: 64px;
    height: 64px;
  }
}

/* ---- UX audit fixes (operator 2026-05-03, GRAEAE + Codex) ---- */
/* Codex measured cue text at 11.5px on mobile — bump to 14px so it's
   discoverable below the persona-prose narrative. Drop the redundant
   chevron at this size: the text "View N cards" + open/close summary
   marker is enough affordance. */
@media (max-width: 768px) {
  .dimension__expand-cue {
    font-size: 14px !important;
    font-weight: 700 !important;
  }
  .dimension__expand-chevron {
    display: none !important;
  }
}
.dimension__expand-cue {
  font-weight: 600;
}

/* ==== Combo-badge matrix + card grid (operator 2026-05-03) ============
   Bad Actors merged dim and Chain Activity dim use pre-rendered combo
   SVGs keyed by signature (e.g. bad-actors-HCR.svg). Cards reference
   ``card.combo_badge_url`` which the template renders as <img>. */
.combo-badge {
  display: inline-block;
  vertical-align: middle;
  height: 42px;
  width: auto;
  max-width: 132px;
}
.combo-badge--block {
  display: block;
  margin: var(--s-2) 0;
}

/* Card-side badge grid (Bad Actors). 3 fixed slots + 1 flex slot for
   sparkline so cards align across the dim regardless of how many
   badges each carries. Empty slots render as nothing — no flow. */
.card-badges {
  display: grid;
  grid-template-columns: var(--badge-w, 92px) 1fr;
  gap: var(--s-3);
  align-items: center;
  padding: var(--s-2) 0;
}
.card-badges__pill {
  /* the combo-badge slot */
}
.card-badges__sparkline {
  /* the sparkline slot */
  min-width: 0;
  overflow: hidden;
}
@media (max-width: 480px) {
  .card-badges {
    grid-template-columns: 1fr;
  }
}

/* Chain Activity card group treatment. Brand summary card uses a
   distinct chrome (chain group) to read as cross-cutting. */
.dimension--chain {
  background: var(--paper);
  border-left: 3px solid #9333ea;
  padding-left: var(--s-3);
}
.chain-licensee {
  margin-top: var(--s-3);
  padding-left: var(--s-3);
  border-left: 1px dashed var(--rule);
}
.chain-licensee__head {
  font-weight: 600;
  font-size: 0.95em;
  color: var(--ink);
}
.chain-locations {
  margin: var(--s-2) 0 0 var(--s-4);
  font-size: 0.9em;
  color: var(--ink-muted);
}

/* ==== V3 polish (operator 2026-05-03) =================================
   GRAEAE consult recommendations:
   (1) License-track chrome — wrap the 5 license-event dims (Lapsed,
       Confirmed-closed, Off-the-radar, Owner-changed, New-licenses)
       in a shared --navy left-border frame so the administrative band
       reads as a single editorial group, distinct from the health/
       inspection band.
   (2) Paper tiers 3→2 — drop the middle --paper-2 stripe so the
       homepage doesn't fragment into 3 visual layers. Keep --paper
       (white) as the body and --paper-3 (light gray) only for major
       section heads.
   (3) Combo-badge sizing — clamp combo-badge width inside cards so
       the matrix SVG sits at a readable scale without overflowing.  */

/* (1) license-track chrome */
.dimension-block .dimension--group-license {
  border-left: 3px solid #1A3D6D;
  background: var(--paper);
}
.dimension-block .dimension--group-license .dimension__head {
  border-bottom-color: #1A3D6D;
}

/* Health band gets a complementary subtle red-tinted left rule */
.dimension-block .dimension--group-health {
  border-left: 3px solid var(--rule);
}

/* Chain band — distinct so the cross-cutting dim reads as its own thing */
.dimension-block .dimension--group-chain {
  border-left: 3px solid #9333ea;
  background: var(--paper);
}

/* (2) paper tiers 3→2 — collapse --paper-2 mid-tier to --paper.
       This keeps backwards compat for any explicit --paper-2 reference
       (just makes it identical to --paper) without removing the var. */
:root {
  --paper-2: var(--paper);
}

/* (3) combo-badge sizing in cards */
.card__combo-badge {
  margin: var(--s-2) 0;
}
.card__combo-badge .combo-badge {
  height: 36px;
  width: auto;
  display: block;
}
@media (max-width: 480px) {
  .card__combo-badge .combo-badge {
    height: 32px;
  }
}

/* Worsts lifetime severity sparkline + narrative summary
   (operator 2026-05-04). Tells the reader WHY each card is
   worst-of-worst — the badge shows the combo, the spark shows
   the 11-year arc, the caption names the inflection. */
.worsts-spark {
  margin: var(--s-2) 0 var(--s-3);
  padding: var(--s-1) var(--s-2);
  background: rgba(255, 87, 34, 0.04);   /* faint sunburst tint */
  border-left: 3px solid #ff5722;
  border-radius: 2px;
}
.worsts-spark__svg {
  display: block;
  width: 100%;
  max-width: 264px;
  height: 36px;
  margin: 0 0 4px;
}
.worsts-spark__summary {
  margin: 0;
  font-family: var(--font-display);
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink);
}
.worsts-spark__summary--chronic    { color: #8B1818; }
.worsts-spark__summary--climbing   { color: #dc2626; }
.worsts-spark__summary--collapsing { color: #ff5722; }
.worsts-spark__summary--persistent { color: #6B5B4E; }
.worsts-spark__caption {
  margin: 2px 0 0;
  font-size: 0.66rem;
  font-style: italic;
  color: var(--ink-muted);
  letter-spacing: 0.02em;
}
/* Operator 2026-05-05: time markers on the lifetime sparkline so readers
   know the timescale. Year ticks under the line + start/end labels. */
.worsts-spark__chart-wrap {
  position: relative;
  width: 100%;
  max-width: 264px;
  margin: 0 0 4px;
}
.worsts-spark__year-axis {
  position: relative;
  width: 100%;
  height: 12px;
  margin-top: 1px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 9px;
  font-weight: 700;
  color: var(--ink-muted, #6b7280);
}
.worsts-spark__year-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
  line-height: 1;
}
.worsts-spark__endpoints {
  display: flex;
  justify-content: space-between;
  margin-top: 2px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  font-weight: 800;
  color: var(--ink, #111);
}
.worsts-spark__endpoint--start { text-align: left; }
.worsts-spark__endpoint--end { text-align: right; }

/* ==== Chain-activity card detail (operator 2026-05-03) ============
   Per-licensee block inside chain-activity cards. Each licensee shows
   its location count + summary flags + scrollable list of locations
   with per-location signal pills (corp_dissolved, lapsed, viols, etc.). */

.card__details--licensees {
  margin-top: var(--s-3);
}
.card__details--licensees > summary {
  font-weight: 600;
  cursor: pointer;
}
.chain-licensee {
  margin: var(--s-3) 0 var(--s-2) 0;
  padding: var(--s-2) var(--s-3);
  border-left: 3px solid var(--rule);
  background: var(--paper);
}
.chain-licensee__head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: baseline;
  margin-bottom: var(--s-2);
  font-size: 0.95em;
}
.chain-licensee__head strong { color: var(--ink); }
.chain-licensee__count {
  color: var(--ink-muted);
  font-size: 0.85em;
}
.chain-licensee__flags {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}
.chain-locations {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.chain-locations__row {
  font-size: 0.85em;
  padding: 2px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
}
.chain-loc__name { font-weight: 500; }
.chain-loc__city { color: var(--ink-muted); }
.chain-locations__more {
  font-size: 0.85em;
  color: var(--ink-muted);
  padding: 2px 0;
}

/* Per-location signal flag pills */
.loc-flag {
  display: inline-block;
  font-size: 0.75em;
  padding: 1px 7px;
  border-radius: 3px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.loc-flag--red    { background: var(--red-bg); color: var(--red); }
.loc-flag--deep   { background: var(--red-bg); color: var(--red-deep); }
.loc-flag--orange { background: var(--amber-bg); color: var(--orange); }
.loc-flag--green  { background: var(--green-bg); color: var(--green); }
.loc-flag--grey   { background: var(--paper-3); color: var(--ink-muted); }

/* ==== Worsts dim chrome (operator 2026-05-03) =========================
   Cross-dim concentration tier — gets distinct visual treatment so
   readers see at a glance that this is the high-water-mark dim, not
   one of the standard 9. Sunburst-orange left rule on paper. */
.dimension-block .dimension--group-worsts {
  border-left: 4px solid #ff5722;
  background: var(--paper);
  box-shadow: 0 1px 0 var(--rule);
}
.dimension-block .dimension--group-worsts .dimension__head {
  border-bottom: 2px solid #ff5722;
}
.dimension-block .dimension--group-worsts .dimension__heading::before {
  content: "⚠  ";
  color: #ff5722;
  font-weight: 900;
}
.dimension-block .dimension--group-worsts .jump-nav__link[data-group="worsts"],
.jump-nav__link[data-group="worsts"] {
  background: #ff5722;
  color: var(--paper);
  font-weight: 700;
  border: 1px solid #ff5722;
}

/* Worsts card — flag-detail row + tier badge below combo-badge */
.card .worsts-flag-detail {
  font-size: 0.8em;
  color: #ff5722;
  font-weight: 600;
  margin-top: var(--s-1);
  letter-spacing: 0.01em;
}
.card .worsts-tier {
  display: inline-block;
  padding: 2px 8px;
  background: #ff5722;
  color: var(--paper);
  font-size: 0.72em;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 3px;
  margin-right: var(--s-2);
  vertical-align: middle;
}
.card .worsts-tier--worst-3 { background: #ff5722; }
.card .worsts-tier--acute { background: #dc2626; }
.card .worsts-tier--admin-bad { background: #EA580C; }
.card .worsts-tier--gone-quiet { background: #1A3D6D; }
.card .worsts-tier--admin-acute { background: #fbbf24; }

/* ==== Distressed risk-stack badges + EOR callback-overdue === */
.card .distress-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--s-2);
}
.card .distress-badge {
  display: inline-block;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-tag);
  font-size: var(--badge-font);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.card .distress-badge--prior_violators   { background: var(--red-bg); color: var(--red); border: 1px solid var(--red); }
.card .distress-badge--high_risk_ops     { background: rgba(234, 88, 12, 0.10); color: #EA580C; border: 1px solid #EA580C; }
.card .distress-badge--severe_neglect_2yr { background: var(--paper-3); color: var(--ink-muted); border: 1px solid var(--rule); }
.card .distress-badge--independent       { background: var(--yellow-bg); color: var(--yellow); border: 1px solid var(--yellow); }

/* Unified Closures severity/source badges. */
.card .closure-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--s-2);
}

.closure-confidence-badge {
  margin-right: var(--s-2);
  margin-bottom: var(--s-1);
}

.closure-signal-tier {
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}

.closure-signal-tier__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2);
  cursor: pointer;
  color: var(--ink);
}

.closure-signal-tier__title {
  font-family: var(--font-display);
  font-weight: 800;
}

.closure-signal-tier__badge {
  display: inline-block;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-tag);
  border: 1px solid var(--amber);
  background: var(--amber-bg);
  color: var(--amber);
  font-size: var(--badge-font);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.closure-signal-tier__count {
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
}

/* Unified Openings source/confidence badges. */
.card .opening-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: var(--s-2);
}

/* EOR callback-overdue indicator on EOR cards. When DBPR's regulatory
   followup is past 14d (warning) or 30d (severe), surface inline. */
.card .callback-overdue {
  display: inline-block;
  margin-left: var(--s-2);
  padding: 1px 8px;
  border-radius: 3px;
  font-size: 0.78em;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  vertical-align: middle;
}
.card .callback-overdue--warning { background: var(--amber-bg); color: var(--orange); border: 1px solid var(--orange); }
.card .callback-overdue--severe  { background: var(--red-deep); color: var(--paper); border: 1px solid var(--red-deep); }
.risk-card-badges .callback-overdue {
  margin-left: 0;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  font-size: var(--badge-font);
  line-height: 1.1;
  white-space: normal;
}

/* ==== Dimension card name + link text colors (operator 2026-05-04) ====
   Scoped to the dimension wrappers only: restaurant names and in-card link
   CTAs pick up the section color without changing addresses, cities, chips,
   badge labels, or link text-decoration.

   Contrast audit against --paper #FFFFFF:
   - Canonical colors below 4.5:1 use darker same-family text variants here:
     #ff5722 -> #c2410c, #EA580C -> #c2410c, #F97316 -> #c2410c,
     #16a34a -> #15803d, #06b6d4 -> #0e7490.
   - #fbbf24 audits at 1.67:1 on white, but it is a badge background, not a
     restaurant-name or link-CTA text color, so it is intentionally untouched. */

/* under-emergency-order: canonical #dc2626, 4.83:1 on white. */
.dimension-block[data-dim="under-emergency-order"] .card__link,
.dimension-block[data-dim="under-emergency-order"] .card__source-badge-link,
.dimension-block[data-dim="under-emergency-order"] .card__verify-link,
.dimension-block[data-dim="under-emergency-order"] .card__fb-link,
.dimension-block[data-dim="under-emergency-order"] .card__news-link,
.dimension-block[data-dim="under-emergency-order"] .sunbiz-link,
.dimension-block[data-dim="under-emergency-order"] .card-link,
.dimension--under-emergency-order .card__link,
.dimension--under-emergency-order .card__source-badge-link,
.dimension--under-emergency-order .card__verify-link,
.dimension--under-emergency-order .card__fb-link,
.dimension--under-emergency-order .card__news-link,
.dimension--under-emergency-order .sunbiz-link,
.dimension--under-emergency-order .card-link {
  color: #dc2626;
}

/* bad-actors: canonical #8B1818, 9.37:1 on white. */
.dimension-block[data-dim="bad-actors"] .card__link,
.dimension-block[data-dim="bad-actors"] .card__source-badge-link,
.dimension-block[data-dim="bad-actors"] .card__verify-link,
.dimension-block[data-dim="bad-actors"] .card__fb-link,
.dimension-block[data-dim="bad-actors"] .card__news-link,
.dimension-block[data-dim="bad-actors"] .sunbiz-link,
.dimension-block[data-dim="bad-actors"] .card-link,
.dimension--bad-actors .card__link,
.dimension--bad-actors .card__source-badge-link,
.dimension--bad-actors .card__verify-link,
.dimension--bad-actors .card__fb-link,
.dimension--bad-actors .card__news-link,
.dimension--bad-actors .sunbiz-link,
.dimension--bad-actors .card-link {
  color: #8B1818;
}

/* worst-offenders: canonical #8B1818, 9.37:1 on white. */
.dimension-block[data-dim="worst-offenders"] .card__link,
.dimension-block[data-dim="worst-offenders"] .card__source-badge-link,
.dimension-block[data-dim="worst-offenders"] .card__verify-link,
.dimension-block[data-dim="worst-offenders"] .card__fb-link,
.dimension-block[data-dim="worst-offenders"] .card__news-link,
.dimension-block[data-dim="worst-offenders"] .sunbiz-link,
.dimension-block[data-dim="worst-offenders"] .card-link,
.dimension--worst-offenders .card__link,
.dimension--worst-offenders .card__source-badge-link,
.dimension--worst-offenders .card__verify-link,
.dimension--worst-offenders .card__fb-link,
.dimension--worst-offenders .card__news-link,
.dimension--worst-offenders .sunbiz-link,
.dimension--worst-offenders .card-link {
  color: #8B1818;
}

/* worsts: canonical #ff5722 is 3.16:1 on white, so text uses #c2410c. */
.dimension-block[data-dim="worsts"] .card__link,
.dimension-block[data-dim="worsts"] .card__source-badge-link,
.dimension-block[data-dim="worsts"] .card__verify-link,
.dimension-block[data-dim="worsts"] .card__fb-link,
.dimension-block[data-dim="worsts"] .card__news-link,
.dimension-block[data-dim="worsts"] .sunbiz-link,
.dimension-block[data-dim="worsts"] .card-link,
.dimension--worsts .card__link,
.dimension--worsts .card__source-badge-link,
.dimension--worsts .card__verify-link,
.dimension--worsts .card__fb-link,
.dimension--worsts .card__news-link,
.dimension--worsts .sunbiz-link,
.dimension--worsts .card-link,
.dimension-block .dimension--group-worsts .card__link,
.dimension-block .dimension--group-worsts .card__source-badge-link,
.dimension-block .dimension--group-worsts .card__verify-link,
.dimension-block .dimension--group-worsts .card__fb-link,
.dimension-block .dimension--group-worsts .card__news-link,
.dimension-block .dimension--group-worsts .sunbiz-link,
.dimension-block .dimension--group-worsts .card-link {
  color: #c2410c;
}

/* permanent-closures: canonical #6B5B4E, 8.31:1 on white and 7.76:1 on tier-4 tint. */
.dimension-block[data-dim="permanent-closures"] .card__link,
.dimension-block[data-dim="permanent-closures"] .card__source-badge-link,
.dimension-block[data-dim="permanent-closures"] .card__verify-link,
.dimension-block[data-dim="permanent-closures"] .card__fb-link,
.dimension-block[data-dim="permanent-closures"] .card__news-link,
.dimension-block[data-dim="permanent-closures"] .sunbiz-link,
.dimension-block[data-dim="permanent-closures"] .card-link,
.dimension--permanent-closures .card__link,
.dimension--permanent-closures .card__source-badge-link,
.dimension--permanent-closures .card__verify-link,
.dimension--permanent-closures .card__fb-link,
.dimension--permanent-closures .card__news-link,
.dimension--permanent-closures .sunbiz-link,
.dimension--permanent-closures .card-link {
  color: #6B5B4E;
}

/* closures: canonical #6B5B4E, 8.31:1 on white. */
.dimension-block[data-dim="closures"] .card__link,
.dimension-block[data-dim="closures"] .card__source-badge-link,
.dimension-block[data-dim="closures"] .card__verify-link,
.dimension-block[data-dim="closures"] .card__fb-link,
.dimension-block[data-dim="closures"] .card__news-link,
.dimension-block[data-dim="closures"] .sunbiz-link,
.dimension-block[data-dim="closures"] .card-link,
.dimension--closures .card__link,
.dimension--closures .card__source-badge-link,
.dimension--closures .card__verify-link,
.dimension--closures .card__fb-link,
.dimension--closures .card__news-link,
.dimension--closures .sunbiz-link,
.dimension--closures .card-link {
  color: #6B5B4E;
}

/* recent-failures: canonical #F97316 is 2.80:1 on white, so text uses #c2410c. */
.dimension-block[data-dim="recent-failures"] .card__link,
.dimension-block[data-dim="recent-failures"] .card__source-badge-link,
.dimension-block[data-dim="recent-failures"] .card__verify-link,
.dimension-block[data-dim="recent-failures"] .card__fb-link,
.dimension-block[data-dim="recent-failures"] .card__news-link,
.dimension-block[data-dim="recent-failures"] .sunbiz-link,
.dimension-block[data-dim="recent-failures"] .card-link,
.dimension--recent-failures .card__link,
.dimension--recent-failures .card__source-badge-link,
.dimension--recent-failures .card__verify-link,
.dimension--recent-failures .card__fb-link,
.dimension--recent-failures .card__news-link,
.dimension--recent-failures .sunbiz-link,
.dimension--recent-failures .card-link {
  color: #c2410c;
}

/* most-improved: canonical #16a34a is 3.30:1 on white, so text uses #15803d. */
.dimension-block[data-dim="most-improved"] .card__link,
.dimension-block[data-dim="most-improved"] .card__source-badge-link,
.dimension-block[data-dim="most-improved"] .card__verify-link,
.dimension-block[data-dim="most-improved"] .card__fb-link,
.dimension-block[data-dim="most-improved"] .card__news-link,
.dimension-block[data-dim="most-improved"] .sunbiz-link,
.dimension-block[data-dim="most-improved"] .card-link,
.dimension--most-improved .card__link,
.dimension--most-improved .card__source-badge-link,
.dimension--most-improved .card__verify-link,
.dimension--most-improved .card__fb-link,
.dimension--most-improved .card__news-link,
.dimension--most-improved .sunbiz-link,
.dimension--most-improved .card-link {
  color: #15803d;
}

/* clean-plates: canonical #16a34a is 3.30:1 on white, so text uses #15803d. */
.dimension-block[data-dim="clean-plates"] .card__link,
.dimension-block[data-dim="clean-plates"] .card__source-badge-link,
.dimension-block[data-dim="clean-plates"] .card__verify-link,
.dimension-block[data-dim="clean-plates"] .card__fb-link,
.dimension-block[data-dim="clean-plates"] .card__news-link,
.dimension-block[data-dim="clean-plates"] .sunbiz-link,
.dimension-block[data-dim="clean-plates"] .card-link,
.dimension--clean-plates .card__link,
.dimension--clean-plates .card__source-badge-link,
.dimension--clean-plates .card__verify-link,
.dimension--clean-plates .card__fb-link,
.dimension--clean-plates .card__news-link,
.dimension--clean-plates .sunbiz-link,
.dimension--clean-plates .card-link {
  color: #15803d;
}

/* openings: canonical #06b6d4 is 2.43:1 on white, so text uses #0e7490. */
.dimension-block[data-dim="openings"] .card__link,
.dimension-block[data-dim="openings"] .card__source-badge-link,
.dimension-block[data-dim="openings"] .card__verify-link,
.dimension-block[data-dim="openings"] .card__fb-link,
.dimension-block[data-dim="openings"] .card__news-link,
.dimension-block[data-dim="openings"] .sunbiz-link,
.dimension-block[data-dim="openings"] .card-link,
.dimension--openings .card__link,
.dimension--openings .card__source-badge-link,
.dimension--openings .card__verify-link,
.dimension--openings .card__fb-link,
.dimension--openings .card__news-link,
.dimension--openings .sunbiz-link,
.dimension--openings .card-link {
  color: #0e7490;
}

/* new-licenses: canonical #06b6d4 is 2.43:1 on white, so text uses #0e7490. */
.dimension-block[data-dim="new-licenses"] .card__link,
.dimension-block[data-dim="new-licenses"] .card__source-badge-link,
.dimension-block[data-dim="new-licenses"] .card__verify-link,
.dimension-block[data-dim="new-licenses"] .card__fb-link,
.dimension-block[data-dim="new-licenses"] .card__news-link,
.dimension-block[data-dim="new-licenses"] .sunbiz-link,
.dimension-block[data-dim="new-licenses"] .card-link,
.dimension--new-licenses .card__link,
.dimension--new-licenses .card__source-badge-link,
.dimension--new-licenses .card__verify-link,
.dimension--new-licenses .card__fb-link,
.dimension--new-licenses .card__news-link,
.dimension--new-licenses .sunbiz-link,
.dimension--new-licenses .card-link {
  color: #0e7490;
}

/* ghost-licenses: canonical #64748b, 4.76:1 on white. */
.dimension-block[data-dim="ghost-licenses"] .card__link,
.dimension-block[data-dim="ghost-licenses"] .card__source-badge-link,
.dimension-block[data-dim="ghost-licenses"] .card__verify-link,
.dimension-block[data-dim="ghost-licenses"] .card__fb-link,
.dimension-block[data-dim="ghost-licenses"] .card__news-link,
.dimension-block[data-dim="ghost-licenses"] .sunbiz-link,
.dimension-block[data-dim="ghost-licenses"] .card-link,
.dimension--ghost-licenses .card__link,
.dimension--ghost-licenses .card__source-badge-link,
.dimension--ghost-licenses .card__verify-link,
.dimension--ghost-licenses .card__fb-link,
.dimension--ghost-licenses .card__news-link,
.dimension--ghost-licenses .sunbiz-link,
.dimension--ghost-licenses .card-link {
  color: #64748b;
}

/* lost-licenses: canonical #1A3D6D, 10.87:1 on white. */
.dimension-block[data-dim="lost-licenses"] .card__link,
.dimension-block[data-dim="lost-licenses"] .card__source-badge-link,
.dimension-block[data-dim="lost-licenses"] .card__verify-link,
.dimension-block[data-dim="lost-licenses"] .card__fb-link,
.dimension-block[data-dim="lost-licenses"] .card__news-link,
.dimension-block[data-dim="lost-licenses"] .sunbiz-link,
.dimension-block[data-dim="lost-licenses"] .card-link,
.dimension--lost-licenses .card__link,
.dimension--lost-licenses .card__source-badge-link,
.dimension--lost-licenses .card__verify-link,
.dimension--lost-licenses .card__fb-link,
.dimension--lost-licenses .card__news-link,
.dimension--lost-licenses .sunbiz-link,
.dimension--lost-licenses .card-link {
  color: #1A3D6D;
}

/* chain-activity: canonical #9333ea, 5.38:1 on white. */
.dimension-block[data-dim="chain-activity"] .card__link,
.dimension-block[data-dim="chain-activity"] .card__source-badge-link,
.dimension-block[data-dim="chain-activity"] .card__verify-link,
.dimension-block[data-dim="chain-activity"] .card__fb-link,
.dimension-block[data-dim="chain-activity"] .card__news-link,
.dimension-block[data-dim="chain-activity"] .sunbiz-link,
.dimension-block[data-dim="chain-activity"] .card-link,
.dimension--chain-activity .card__link,
.dimension--chain-activity .card__source-badge-link,
.dimension--chain-activity .card__verify-link,
.dimension--chain-activity .card__fb-link,
.dimension--chain-activity .card__news-link,
.dimension--chain-activity .sunbiz-link,
.dimension--chain-activity .card-link {
  color: #9333ea;
}

/* Keep the existing filled-pill hover contrast for tray links. */
.dimension-block[data-dim] .card__link:hover,
.dimension-block .dimension .card__link:hover {
  color: var(--paper);
}

.dim__new-badge {
  display: inline-flex;
  align-items: center;
  margin-left: 0.45em;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border: 1px solid rgba(17, 24, 39, 0.18);
  border-radius: var(--badge-radius-tag);
  background: #fff7ed;
  color: #9a3412;
  font-family: var(--font-sans);
  font-size: var(--badge-font);
  font-weight: 800;
  line-height: 1.25;
  text-transform: uppercase;
  vertical-align: middle;
}
.risk-card-badges .dim__new-badge {
  margin-left: 0;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  font-size: var(--badge-font);
  line-height: 1.1;
  white-space: normal;
}

.dim__since-last-visit-caption {
  display: block;
  margin-top: 0.18rem;
  color: var(--ink-muted);
  font-family: var(--font-sans);
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1.3;
  text-transform: none;
}

.dim__since-last-visit-caption[hidden] {
  display: none;
}

.tse-insights {
  margin: 0 0 0.9rem;
  padding: 0.75rem 0.85rem;
  border: 1px solid rgba(14, 124, 102, 0.28);
  border-left: 4px solid #0e7c66;
  border-radius: 6px;
  background: #f0fdfa;
  color: var(--ink);
}

.tse-insights--metro {
  margin: 1rem 0 1.25rem;
}

.tse-insights__kicker {
  display: block;
  color: #0f766e;
  font-family: var(--font-sans);
  font-size: 0.74rem;
  font-weight: 800;
  line-height: 1.2;
  text-transform: uppercase;
}

.tse-insights__list {
  display: grid;
  /* Signals sit SIDE BY SIDE when there is room. This was a single implicit
     column, so each signal was a full-width row with a long tail of empty
     space -- the section grew tall and wasted the width it was given.
     auto-fit + minmax gives two or three columns on a wide viewport and
     collapses to one on a narrow one; the min() stops a phone getting a
     column wider than the screen. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: 0.5rem 1.25rem;
  margin: 0.45rem 0 0;
  padding-left: 1rem;
}

/* ---- forecast chart -------------------------------------------------
   These rules existed ONLY in riskyeats/templates/styles.css, which was not
   the stylesheet the site links (index.html.j2 links static/styles.css and
   _copy_public_static ships riskyeats/static/), so the chart's axis, legend
   and 30-day breakpoints had been rendering unstyled in production. That dead
   copy was DELETED on 2026-08-07; this note records where these came from.
   See the divergence note at the top of this block's sibling rules. */
.tse-insights__spark {
  display: block;
  margin: 0.4rem 0 0.2rem;
  max-width: 100%;
}
.tse-insights__axis {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
  font-size: var(--text-xs);
  color: var(--ink-3, #64748b);
  margin-top: 2px;
  max-width: 264px;
}
.tse-insights__axis span:nth-child(2) { flex: 1 1 auto; text-align: center; }
.tse-insights__ticks {
  position: relative;
  display: block;
  height: 1em;
  max-width: 264px;
  font-size: var(--text-xs);
  color: var(--ink-3, #64748b);
}
.tse-insights__tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
}
.tse-insights__keys {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.75rem;
  margin-top: 0.15rem;
  font-size: var(--text-xs);
  color: var(--ink-3, #64748b);
}
.tse-insights__key { display: inline-flex; align-items: center; gap: 0.3rem; }
.tse-insights__key i {
  display: inline-block;
  width: 0.7rem;
  height: 0.2rem;
  border-radius: 1px;
}

.tse-insights__item {
  display: grid;
  gap: 0.2rem;
  margin: 0;
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.35;
}

.tse-insights__type {
  color: #0f766e;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.tse-insights__headline {
  display: block;
}

.tse-insights__detail,
.tse-insights__meaning,
.tse-insights__why {
  display: block;
  color: var(--ink-muted);
  font-size: 0.86rem;
}

/* ── Dimension card frame + colored expander bars ─────────────────────
   Each dimension-block is a rounded bordered card.
   The summary (expander bar) carries the editorial color.
   overflow:hidden rounds the bar into the card corners.
   Added post-.4, 2026-05-18. */
.dimension-block {
  border: 3px solid var(--rule-strong, #6E6E6E) !important;
  border-radius: 10px !important;
  overflow: hidden !important;
  margin-bottom: var(--s-5) !important;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12) !important;
}
.dimension-block > .dimension > summary.dimension__head {
  padding: var(--s-2) var(--s-3);
  border-bottom: 0;
  margin: 0;
  background: #2B2B2B;
  color: var(--paper);
  cursor: pointer;
  transition: filter 120ms ease;
}
.dimension-block > .dimension > summary.dimension__head:hover { filter: brightness(1.1); }
.dimension-block > .dimension > summary.dimension__head * { color: inherit !important; }
.dimension-block[data-dim="under-emergency-order"] > .dimension > summary.dimension__head { background: var(--dim-red-alert); }
.dimension-block[data-dim="recent-failures"] > .dimension > summary.dimension__head { background: var(--dim-near-miss); }
.dimension-block[data-dim="worst-offenders"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="bad-actors"] > .dimension > summary.dimension__head { background: var(--dim-worst-offenders); }
.dimension-block[data-dim="worsts"] > .dimension > summary.dimension__head { background: #c2410c; }
.dimension-block[data-dim="most-improved"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="clean-plates"] > .dimension > summary.dimension__head { background: var(--dim-most-improved); }
.dimension-block[data-dim="permanent-closures"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="closures"] > .dimension > summary.dimension__head { background: var(--dim-closures); }
.dimension-block[data-dim="ghost-licenses"] > .dimension > summary.dimension__head { background: var(--dim-license-paper); }
.dimension-block[data-dim="lost-licenses"] > .dimension > summary.dimension__head { background: var(--dim-owner-changed); }
.dimension-block[data-dim="openings"] > .dimension > summary.dimension__head,
.dimension-block[data-dim="new-licenses"] > .dimension > summary.dimension__head { background: var(--dim-openings); }
.dimension-block[data-dim="chain-activity"] > .dimension > summary.dimension__head { background: var(--dim-chain-activity); }

/* ----- Distressed Chip-Row (Task #96) ----- */
.distressed-chip-row {
  margin: 0.5rem 0 1rem;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  background: var(--surface-1, #fff7ed);
  border-left: 4px solid #c2410c;
  border-radius: var(--badge-radius-tag);
}
.distressed-chip-row__title {
  margin: 0 0 0.5rem;
  font-size: var(--badge-font);
  font-weight: 600;
  color: #7c2d12;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.distressed-chip-row__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.distressed-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  background: #fff;
  border: 1px solid #fed7aa;
  color: #7c2d12;
  text-decoration: none;
  font-size: var(--badge-font);
  transition: background 120ms ease, border-color 120ms ease;
}
.distressed-chip:hover,
.distressed-chip:focus {
  background: #fff7ed;
  border-color: #fb923c;
  outline: 2px solid transparent;
}
.distressed-chip__count {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  font-size: var(--badge-font);
}
.distressed-chip__label {
  color: #9a3412;
  font-weight: 500;
}
.distressed-chip--total  { border-color: #fb923c; }
.distressed-chip--solo   { border-color: #f87171; }
.distressed-chip--chain  { border-color: #a78bfa; }
.distressed-chip--total:hover  { border-color: #ea580c; }
.distressed-chip--solo:hover   { border-color: #dc2626; }
.distressed-chip--chain:hover  { border-color: #7c3aed; }


/* Safety-first card summary: risk state, inspection timing, HP counts, and
   closure-order status appear before cuisine/brand/link metadata. */
.card__safety {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--s-2);
  margin: 0;
  padding: var(--s-3);
  border: 1px solid var(--rule);
  border-left: 4px solid var(--red);
  background: var(--paper-2);
}
.card__safety-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.card__safety-item dt {
  font-size: var(--text-xs);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
}
.card__safety-item dd {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.card__secondary {
  margin: 0;
  color: var(--ink-muted);
}
.card__secondary:empty { display: none; }
.card__secondary .card__cuisine { margin: 0; }

/* ---- Unified venue search dropdown (operator 2026-06-20) ----------
   ONE shared interface for /fri/search.html ("Look up a place") + the
   main metro page ("Find a Resto"). Custom debounced results list that
   replaces the native <datalist> (mobile popup obscured the page).
   Class-namespaced "reveal-search" so it looks identical wherever it
   is inlined. Self-contained values (no var() dependency) so it renders
   the same on the standalone search/find pages and the metro page. */
.reveal-search { position: relative; }
.reveal-search__results {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: auto;
  z-index: 60;
  /* Wider than a narrow header input so longer names/meta fit; 2-line rows. */
  min-width: min(560px, 92vw);
  max-width: 92vw;
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  border: 1px solid #d9ded8;
  border-radius: 9px;
  background: #fff;
  box-shadow: 0 8px 28px rgba(15, 23, 42, 0.10);
  max-height: 60vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.reveal-search__results[hidden] { display: none; }
.reveal-search__row {
  display: block;
  padding: 11px 14px;
  border-bottom: 1px solid #eef1ee;
  color: #164e63;
  text-decoration: none;
}
.reveal-search__row:last-child { border-bottom: 0; }
.reveal-search__row:hover,
.reveal-search__row:focus-visible {
  background: #fef2f2;
  outline: none;
}
.reveal-search__row--info {
  color: #1f2937;
  cursor: default;
}
.reveal-search__name { font-weight: 700; line-height: 1.35; white-space: normal; overflow-wrap: anywhere; }
.reveal-search__meta {
  color: #6b7280;
  font-size: 0.85rem;
  margin-top: 2px;
}
.reveal-search__badge {
  display: inline-block;
  font-size: var(--badge-font);
  font-weight: 700;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  margin-left: 6px;
  border-radius: var(--badge-radius-pill);
  background: #fef2f2;
  color: #b91c1c;
  border: 1px solid #fecaca;
  vertical-align: middle;
  white-space: nowrap;
}
/* "Appears in:" chip line below the venue name on container rows. */
.reveal-search__appearances { margin-top: 4px; font-size: 0.85rem; color: #6b7280; }
/* Linked "Appears in" chip — points at the venue's metro briefing. */
a.reveal-search__badge--link { text-decoration: none; cursor: pointer; }
a.reveal-search__badge--link:hover,
a.reveal-search__badge--link:focus-visible { background: #fee2e2; outline: none; }
.reveal-search__empty,
.reveal-search__more {
  padding: 12px 14px;
  color: #6b7280;
  font-size: 0.9rem;
}

/* Big Bet #2 — per-venue detail page links. The card name + the universal
   finder result name link to /venue/<key>.html. Inherit the name styling so
   the link is unobtrusive until hovered/focused. */
.card__name-link,
.vlink {
  color: inherit;
  text-decoration: none;
}
.card__name-link:hover,
.card__name-link:focus,
.vlink:hover,
.vlink:focus {
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* AI-validated provenance (sentinel) — badge pill + one-sentence rationale */
.card__ai-provenance-badge {
  display: inline-block;
  font-size: var(--badge-font);
  font-weight: 700;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  border-radius: var(--badge-radius-pill);
  background: #f5f3ff;
  color: #6d28d9;
  border: 1px solid #8b5cf6;
  vertical-align: middle;
}
.card__ai-rationale {
  margin: 0.35rem 0 0.2rem;
  padding: 0.4rem 0.7rem;
  font-size: 0.86rem;
  font-style: italic;
  color: #4c1d95;
  background: #f5f3ff;
  border-left: 3px solid #8b5cf6;
  border-radius: 0.3rem;
}
.card__ai-rationale-label {
  font-weight: 700;
  font-style: normal;
}

/* Group colorization — tab buttons + matching dimension outlines
   (operator 2026-07-05, palette restored from the 3f36f70 expander-bar
   scheme: alerts red, caution burnt orange, trusted green, new teal). */
.dim-tab[data-tab="news"]      { border-color:#be123c; color:#9f1239; background:#ffe4e6; }
.dim-tab[data-tab="avoid"]     { border-color:#c2410c; color:#9a3412; background:#ffedd5; }
.dim-tab[data-tab="trusted"]   { border-color:#15803d; color:#166534; background:#dcfce7; }
.dim-tab[data-tab="improving"] { border-color:#2563eb; color:#1d4ed8; background:#dbeafe; }
.dim-tab[data-tab="explore"] { border-color:#0e7490; color:#0e7490; background:#ecfeff; }
.dim-tab[data-tab="news"].is-active      { background:#be123c; color:#fff; border-color:#be123c; }
.dim-tab[data-tab="avoid"].is-active     { background:#c2410c; color:#fff; border-color:#c2410c; }
.dim-tab[data-tab="trusted"].is-active   { background:#15803d; color:#fff; border-color:#15803d; }
.dim-tab[data-tab="improving"].is-active { background:#2563eb; color:#fff; border-color:#2563eb; }
.dim-tab[data-tab="explore"].is-active { background:#0e7490; color:#fff; border-color:#0e7490; }
/* Dimension outline matches the active group color (filter view). */
.dimension-block:has(.dimension--group-news)    { border:1.5px solid #be123c; border-radius:8px; }
.dimension-block:has(.dimension--group-avoid)   { border:1.5px solid #c2410c; border-radius:8px; }
.dimension-block:has(.dimension--group-trusted) { border:1.5px solid #15803d; border-radius:8px; }
.dimension-block:has(.dimension--group-improving) { border:1.5px solid #2563eb; border-radius:8px; }
.dimension-block:has(.dimension--group-closed) { border:1.5px solid #3f3f46; border-radius:8px; }
.dimension-block:has(.dimension--group-explore) { border:1.5px solid #0e7490; border-radius:8px; }
.dimension-block:has(.dimension--group-news)    .dim-divider__count { background:#be123c; }
.dimension-block:has(.dimension--group-avoid)   .dim-divider__count { background:#c2410c; }
.dimension-block:has(.dimension--group-trusted) .dim-divider__count { background:#15803d; }
.dimension-block:has(.dimension--group-improving) .dim-divider__count { background:#2563eb; }
.dimension-block:has(.dimension--group-closed) .dim-divider__count { background:#3f3f46; }
.dimension-block:has(.dimension--group-explore) .dim-divider__count { background:#0e7490; }

/* Sub-filter chip colorization — every filter view (operator 2026-07-05).
   Group tint by data-group; per-dimension accents from the canonical
   palette. .is-active fills. Chronic class chips (--active/--multi/
   --mega/--listed) keep their earlier dedicated colors. */
.sub-filter__chip[data-group="news"]    { border-color:#be123c; color:#9f1239; }
.sub-filter__chip[data-group="avoid"]   { border-color:#c2410c; color:#c2410c; }
.sub-filter__chip[data-group="trusted"] { border-color:#15803d; color:#166534; }
.sub-filter__chip[data-group="improving"] { border-color:#2563eb; color:#1d4ed8; }
.sub-filter__chip[data-group="explore"] { border-color:#0e7490; color:#0e7490; }
.sub-filter__chip[data-sub-filter="under-emergency-order"] { border-color:#dc2626; color:#dc2626; }
.sub-filter__chip[data-sub-filter="recent-failures"]       { border-color:#c2410c; color:#c2410c; }
.sub-filter__chip[data-sub-filter="permanent-closures"]    { border-color:#7f1d1d; color:#7f1d1d; }
.sub-filter__chip[data-sub-filter="bad-actors"]            { border-color:#7f1d1d; color:#7f1d1d; }
.sub-filter__chip[data-sub-filter="most-improved"]         { border-color:#2563eb; color:#1d4ed8; }
.sub-filter__chip[data-sub-filter="clean-plates"]          { border-color:#16a34a; color:#16a34a; }
.sub-filter__chip[data-sub-filter="lost-licenses"]         { border-color:#1e3a5f; color:#1e3a5f; }
.sub-filter__chip[data-sub-filter="openings"]              { border-color:#0e7490; color:#0e7490; }
.sub-filter__chip[data-group="news"].is-active    { background:#be123c; color:#fff; border-color:#be123c; }
.sub-filter__chip[data-group="avoid"].is-active   { background:#c2410c; color:#fff; border-color:#c2410c; }
.sub-filter__chip[data-group="trusted"].is-active { background:#15803d; color:#fff; border-color:#15803d; }
.sub-filter__chip[data-group="improving"].is-active { background:#2563eb; color:#fff; border-color:#2563eb; }
.sub-filter__chip[data-group="explore"].is-active { background:#0e7490; color:#fff; border-color:#0e7490; }
.sub-filter__chip[data-sub-filter="under-emergency-order"].is-active { background:#dc2626; color:#fff; border-color:#dc2626; }
.sub-filter__chip[data-sub-filter="recent-failures"].is-active       { background:#c2410c; color:#fff; border-color:#c2410c; }
.sub-filter__chip[data-sub-filter="permanent-closures"].is-active    { background:#7f1d1d; color:#fff; border-color:#7f1d1d; }
.sub-filter__chip[data-sub-filter="bad-actors"].is-active            { background:#7f1d1d; color:#fff; border-color:#7f1d1d; }
.sub-filter__chip[data-sub-filter="most-improved"].is-active         { background:#166534; color:#fff; border-color:#166534; }
.sub-filter__chip[data-sub-filter="clean-plates"].is-active          { background:#16a34a; color:#fff; border-color:#16a34a; }
.sub-filter__chip[data-sub-filter="lost-licenses"].is-active         { background:#1e3a5f; color:#fff; border-color:#1e3a5f; }
.sub-filter__chip[data-sub-filter="openings"].is-active              { background:#0e7490; color:#fff; border-color:#0e7490; }

/* Self-contained share buttons (AddToAny replacement, 2026-07-05). */
.share-row { display:flex; gap:6px; align-items:center; }
.share-btn {
  display:inline-flex; align-items:center; justify-content:center;
  width:26px; height:26px; border-radius:50%;
  text-decoration:none; line-height:1;
}
.share-btn:hover { filter:brightness(1.15); }

/* Pest evidence surfacing (operator 2026-07-05). */
.severity-bar__pest {
  display:inline-block; margin-left:.5rem; padding:.05rem .45rem;
  font-size:.72rem; font-weight:800; letter-spacing:.03em;
  color:#fff; background:#7f1d1d; border-radius:99px; vertical-align:middle;
}
.violation--pest { background:#fef2f2; border-radius:.3rem; }

/* Mobile-vendor marker (operator 2026-08-03). Neutral slate, deliberately NOT
   a severity colour: being a food truck is a licence class, not a risk finding,
   and colouring it red would turn a factual marker into an accusation. Sits in
   the header badge list rather than beside the score, because the score is
   suppressed on exactly the closure and lifecycle cards where it matters most. */
.card__venue-kind {
  display:inline-block; padding:.05rem .45rem;
  font-size:.72rem; font-weight:800; letter-spacing:.03em;
  color:#0f172a; background:#e2e8f0; border-radius:99px; vertical-align:middle;
}

/* Visible violation-count chips (operator 2026-07-05). */
.card__counts-row { display:flex; gap:6px; flex-wrap:wrap; margin:.35rem 0 .2rem; }
.count-chip {
  display:inline-block; padding: var(--badge-pad-y) var(--badge-pad-x); border-radius: var(--badge-radius-pill);
  font-size: var(--badge-font); font-weight:800; letter-spacing:.02em; line-height:1.4;
  border:1px solid transparent;
}
.count-chip--hp   { background:#fef2f2; color:#b91c1c; border-color:#fecaca; }
.count-chip--int  { background:#fff7ed; color:#c2410c; border-color:#fed7aa; }
.count-chip--bas  { background:#f1f5f9; color:#475569; border-color:#cbd5e1; }
.count-chip--pest { background:#7f1d1d; color:#fff; border-color:#7f1d1d; }

/* Header redesign (2026-07-05): compact share/follow cluster. */
.header-actions {
  display:flex; align-items:center; justify-content:flex-end; gap:8px;
  padding:.2rem 1rem; position:relative;
}
.header-actions__share {
  display:inline-flex; align-items:center; gap:5px;
  font:inherit; font-size:.82rem; font-weight:700;
  /* .25rem -> .4rem vertical padding (operator 2026-08-21, mobile
     copy-density audit: this rendered ~31px next to Near Me's ~37px --
     same header row, visibly different heights. Matches Near Me's own
     .4rem .7rem exactly so the two header pills read as one family. */
  padding:.4rem .7rem; border:1px solid #cbd5e1; border-radius:99px;
  background:#f8fafc; color:#334155; cursor:pointer;
}
.header-actions__share:hover { background:#eef2f7; }
.share-pop {
  position:absolute; top:100%; right:1rem; z-index:60;
  display:flex; gap:6px; padding:.5rem .6rem;
  background:#fff; border:1px solid #cbd5e1; border-radius:12px;
  box-shadow:0 6px 20px rgba(15,23,42,.15);
}
.header-actions__follow { display:flex; align-items:center; gap:6px; }
.header-actions__follow .follow-link { color:#64748b; display:inline-flex; }
.header-actions__follow .follow-link:hover { color:#0f172a; }

/* Mobile header decrowd pass 2 (operator screenshots 2026-07-05 21:15):
   the fixed-position text-size widget floated OVER the NOTICE banner
   text on phones; the banner itself was oversized. On mobile the
   widget becomes a slim in-flow row (own line, right-aligned, label
   dropped) and the banner compacts. Desktop unchanged. */
@media (max-width: 767px) {
  /* Operator 2026-08-11: the widget's own full-width top row was the first
     thing a phone reader saw. A small fixed pill at the bottom-right costs
     zero vertical space and stays reachable one-handed. */
  .fz-selector {
    position: fixed;
    top: auto;
    bottom: calc(var(--s-2, 8px) + env(safe-area-inset-bottom, 0px));
    right: var(--s-2, 8px);
    display: inline-flex;
    width: max-content;
    margin: 0;
    padding: 2px 6px;
    opacity: .92;
  }
  .fz-selector__label { display: none; }
  .stale-banner { padding: .4rem .75rem; font-size: .8rem; line-height: 1.35; }
  .stale-banner strong { margin-right: .35rem; }
}

/* UX fixes 2026-07-06: hidden popover must stay hidden; mobile nav strip needs specificity over .metro-command__nav */
.share-pop[hidden] { display: none !important; }

/* ---- rules recovered from riskyeats/templates/styles.css ------------------
   That file was NOT deployed (index.html.j2 links static/styles.css and
   _copy_public_static ships riskyeats/static/), so everything below was
   written, reviewed and never seen by a reader. Each one was checked against
   the live homepage HTML before porting — these classes are emitted today.
   The dead copy was DELETED on 2026-08-07 so nobody can edit it again; this
   note is kept because it explains where these rules came from. */

/* Emergency-order tier badge. The whole .eo-tier family had ZERO rules in the
   shipped stylesheet, so an EOS badge rendered with no styling at all. */
.eo-tier--eos {
  background: #7f1d1d;
  color: #fff;
  border-color: #7f1d1d;
  margin-left: 4px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}

/* Disciplinary-fine (RDAR) badge — also completely unstyled in production. */
.rdar-badge {
  margin: 0.4rem 0 0.6rem;
  padding: var(--badge-pad-y) var(--badge-pad-x);
  background: color-mix(in srgb, var(--red) 8%, var(--paper));
  border-left: 4px solid var(--red);
  border-radius: var(--badge-radius-tag);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.rdar-badge .risk-band {
  font-size: var(--badge-font);
  padding: var(--badge-pad-y) var(--badge-pad-x);
}

/* Desktop head band for the blog teaser. Without this the head is an avatar
   plus two short stacked lines, which on a 1280px container reads as a narrow
   orphan with most of the row empty — the "takes up too much space" report.
   Putting the title and secondary CTA on one band uses the width and drops a
   row of height. Mobile keeps the stacked layout. */
@media (min-width: 900px) {
  .todays-blog__head {
    flex-wrap: nowrap;
  }
  .todays-blog__head-text {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-3);
    flex-wrap: wrap;
  }
  .todays-blog__head-text .todays-blog__kicker {
    order: -1;
    flex: 1 0 100%;
  }
  .todays-blog__title {
    flex: 1 1 auto;
  }
}

/* Alcohol chip — rides alongside the cuisine kicker. Same muted weight as the
   cuisine label: it is an attribute of the venue, not a finding about it, and
   must not compete with the risk chip. Glyphs are cumulative for full liquor
   (wine + spirits); package-sales series get a trolley and never a pour glyph. */
.card__alcohol { white-space: nowrap; }
.card__alcohol-emoji { font-size: 1em; letter-spacing: 1px; }
.card__alcohol-label { color: var(--ink-2); }
.card__cuisine-sep { opacity: .5; margin: 0 2px; }

/* Revoked alcohol licence — set only when NO live licence resolves to the
   venue (see _alcohol_block). Styled as an adverse fact, in the same register
   as the admin-complaint notation rather than as an alarm: it is a licensing
   action, and the card must not read as a verdict about food safety. */
.card__alcohol--revoked .card__alcohol-label,
.card__alcohol-revoked-date { color: var(--red-deep, #7F1D1D); font-weight: 600; }

/* Desktop card rhythm ------------------------------------------------
   A PC is a single reading flow. Its extra width lets facts wrap naturally in
   one card; it must never manufacture fixed-height bands or a dashboard grid.
   This keeps the visual rhythm in the gaps between real blocks, rather than
   leaving blank space inside short cards. */
@media (min-width: 768px) {
  .card__body {
    --card-block-gap: 14px;
    --card-detail-gap: 10px;
    grid-column: 1 / 2;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .card__body > .risk-card-header {
    margin: 0;
    padding-bottom: var(--card-block-gap);
    display: flex;
    /* row is load-bearing: the base .card__head rule sets flex-direction:
       column, and this header carries both classes. In a column container the
       children's flex-basis (18rem, below) becomes HEIGHT, so every title and
       badge list rendered as a 288px-tall band — the desktop whitespace bug
       shipped in d3150aa. */
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 4px 12px;
  }

  .card__body > .risk-card-header > .risk-card-title {
    flex: 1 1 18rem;
    min-width: 0;
  }

  .card__body > .risk-card-header > .risk-card-badges {
    /* Size to content rather than an 18rem basis: the fixed basis forced
       an early internal wrap that stranded the date on its own line under
       the badge pills (Trusted cards, 2026-08-11). */
    flex: 1 1 auto;
    min-width: 0;
    justify-content: flex-start;
    align-items: center;
    max-width: 100%;
  }

  .card__body > .risk-card-header > :is(.card__cuisine, .card__location) {
    flex: 1 0 100%;
  }

  .card__signal {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--card-block-gap);
    margin: 0;
    padding: var(--card-block-gap) 0;
    border-top: 1px solid var(--rule);
  }

  .card__signal > :is(
    .card__stats,
    .grade-medal,
    .card__basic-reason,
    .card__severity,
    .card__disposition,
    .card__safety,
    .card__secondary
  ) {
    margin-block: 0 !important;
  }

  /* A metric uses the same tile geometry in every dimension. This prevents
     optional History, status, and date rows from creating arbitrary wrap
     positions across a desktop grid. */
  .card__signal--primary .card__stats {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 10px 20px !important;
  }
  .card__signal--primary .card__stat {
    flex: 0 1 auto;
  }

  .card__signal--primary .card__stat--inspector-comment {
    flex-basis: 100%;
  }

  .card__mobile-details {
    margin: 0 !important;
    padding-top: var(--card-block-gap);
    border-top: 1px solid var(--rule);
  }

  .card-full-details {
    display: flex;
    flex-direction: column;
    gap: var(--card-detail-gap);
  }

  .card-full-details > * {
    margin-block: 0 !important;
  }

  /* The action row keeps its own rule as the deliberate boundary between
     evidence and controls; the shared gap supplies the preceding whitespace. */
  .card-full-details > .card__actions {
    margin-top: 0 !important;
  }
}

/* Phone card system — every restaurant card, regardless of whether it is an
   inspection, emergency order, closure, license status, trusted venue, or new
   opening, follows the same scan order: identity, decision signal, then
   evidence. This is a deliberate mobile composition, not a desktop card
   squeezed into a narrower column. */
@media (max-width: 767px) {
  .card-stack,
  .more-cards__list {
    gap: 12px;
  }
  .card {
    display: block;
    padding: 12px !important;
    border-radius: 10px;
    contain-intrinsic-size: auto 260px;
  }
  .card__meta {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    justify-content: flex-start !important;
    gap: 4px 6px !important;
    min-width: 0;
    margin: 0 0 6px;
  }
  .card__section,
  .card__letter,
  .risk-band,
  .dimension-badge {
    flex: 0 0 auto;
  }
  .risk-card-header {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
  }
  /* Raised with the desktop size (operator 2026-08-17, twice -- 1.24rem was
     set against the earlier 1.42rem desktop floor and left behind when that
     floor moved to 1.8rem, which put the phone name BELOW the old desktop
     size while the ask was to make it bigger). Scaled by the same ~1.27x the
     desktop rule took: 1.24 -> 1.55rem.

     Still kept BELOW the desktop floor, for the reason this block exists: a
     phone column is ~340px wide, and a long venue name at desktop size wraps
     to three lines and pushes the record itself under the fold. */
  .risk-card-title,
  .card__name {
    font-size: 1.55rem;
    line-height: 1.18;
  }
  .risk-card-badges {
    justify-content: flex-start;
    gap: 4px;
    padding: 0;
  }
  .dimension-badge,
  .card__venue-kind,
  .card__ai-provenance-badge {
    font-size: 0.68rem;
  }
  .card__location,
  .card__cuisine,
  .card__address {
    font-size: 0.82rem;
    line-height: 1.35;
  }
  .card__basic-reason {
    margin: 8px 0 0;
    font-size: 0.9rem;
    line-height: 1.35;
  }
  .card__severity {
    margin: 10px 0 6px;
  }
  .severity-bar__head {
    margin-bottom: 8px;
  }
  .card-trend {
    margin-top: 8px;
    padding: 7px 9px;
  }
  .card__stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 12px !important;
    margin-top: 8px;
  }
  .card__stat {
    min-width: 0;
  }
  .card__stat--inspector-comment {
    grid-column: 1 / -1;
  }
  .card-face-nav {
    gap: 4px;
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
  .card-face-nav__button { min-height: 28px; padding: 3px 8px; }
  .card__stat dt {
    font-size: 0.62rem;
    letter-spacing: 0.07em;
  }
  .card__stat dd {
    font-size: 0.88rem;
    line-height: 1.3;
  }
  .card__safety {
    grid-template-columns: 1fr;
    gap: 8px;
    margin-top: 8px;
    padding: 9px 10px;
  }
  .card__counts-row,
  .card__method-flags,
  .card__sources-row {
    gap: 4px;
    margin-top: 8px;
  }
  .card__mobile-details {
    margin-top: 8px;
    border-top: 1px solid var(--rule);
  }
  .card__mobile-details-summary {
    padding: 7px 0;
  }
  .card__actions {
    align-items: flex-start;
    gap: 8px;
    margin-top: 8px;
    padding-top: 8px;
  }
  .card__actions .card__report,
  .card__share {
    width: 100%;
    margin-left: 0;
  }
  .card__details,
  .card__details--supporting {
    margin-top: 8px;
    padding-top: 8px;
  }
  .card__more {
    min-height: 36px;
    padding: 6px 0;
  }
  .emergency-preview__card {
    padding: 10px 0 !important;
  }
  .reveal-search__row {
    padding: 10px 12px;
  }
}

/* Group narratives inherit the tab's pale field and strong accent. The
   filter no longer switches from a colored control to an unrelated neutral
   commentary box; the dark prose remains legible at normal body size. */
.dimension--group-news .dimension__narrative {
  --group-narrative-accent: #9f1239;
  background: #fff1f2 !important;
  border-left-color: #be123c !important;
}
.dimension--group-avoid .dimension__narrative {
  --group-narrative-accent: #9a3412;
  background: #fff7ed !important;
  border-left-color: #c2410c !important;
}
.dimension--group-trusted .dimension__narrative {
  --group-narrative-accent: #166534;
  background: #f0fdf4 !important;
  border-left-color: #15803d !important;
}
.dimension--group-improving .dimension__narrative {
  --group-narrative-accent: #1d4ed8;
  background: #eff6ff !important;
  border-left-color: #2563eb !important;
}
.dimension--group-closed .dimension__narrative,
.dimension--group-explore .dimension__narrative {
  --group-narrative-accent: #0f766e;
  background: #ecfeff !important;
  border-left-color: #0e7490 !important;
}
.dimension--group-news .dimension__narrative-label,
.dimension--group-avoid .dimension__narrative-label,
.dimension--group-trusted .dimension__narrative-label,
.dimension--group-improving .dimension__narrative-label,
.dimension--group-closed .dimension__narrative-label,
.dimension--group-explore .dimension__narrative-label,
.dimension--group-news .dimension__narrative-blog-link,
.dimension--group-avoid .dimension__narrative-blog-link,
.dimension--group-trusted .dimension__narrative-blog-link,
.dimension--group-improving .dimension__narrative-blog-link,
.dimension--group-closed .dimension__narrative-blog-link,
.dimension--group-explore .dimension__narrative-blog-link {
  color: var(--group-narrative-accent) !important;
}

/* Five text-only category tabs fit in one phone row. These rules live in the
   shipped stylesheet—not the dynamic panel fragment—so they are present
   before the buttons are inserted. Counts stay on desktop; the wording is
   still the button's accessible name on every device. */
@media (max-width: 767px) {
  .jump-nav-container {
    padding: .25rem .5rem;
  }
  .jump-nav-container::after {
    display: none;
  }
  .jump-nav.jump-nav--tabs {
    display: grid !important;
    /* THREE columns, not five (operator 2026-08-14). The 5-up grid was built
       when there were five tabs; Closed made it six, which laid out 5+1 with a
       lone orphan on the second row. 3+3 is symmetric and gives every label
       more width than the 5-up ever did. */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .2rem;
    overflow: visible !important;
    padding: .15rem 0;
  }
  .jump-nav--tabs .dim-tab {
    justify-content: center;
    min-width: 0;
    min-height: 36px;
    width: 100%;
    /* .1rem side padding + .65rem cap: "Improving" — the longest label —
       fits a 390px 5-up grid without the "Impro…" ellipsis (2026-08-11).
       LEFT UNCHANGED (operator 2026-08-21, mobile copy-density audit
       flagged this as too small at 10.4px): tests/test_mobile_header_
       hierarchy.py::test_mobile_controls_fit_in_a_count_free_tab_row
       asserts this exact literal string, guarding the same "Improving"
       fit this comment describes. A first attempt bumped the cap to
       .7rem and that test caught it -- raising this needs an actual
       rendered check (does "Improving" still fit without truncating in
       the CURRENT 3-column grid, not the 5-column layout this was
       originally tuned against?) before both the CSS and the test can
       move together. Left at .65rem rather than guessing. */
    padding: .25rem .1rem;
    font-size: clamp(.58rem, 2.9vw, .65rem);
    line-height: 1.05;
    letter-spacing: 0;
    white-space: nowrap;
  }
  .jump-nav--tabs .jump-nav__label {
    display: block;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .jump-nav--tabs .jump-nav__count,
  .jump-nav--tabs .jump-nav__icon {
    display: none;
  }
  .jump-nav.jump-nav--tabs .card-face-nav {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .2rem;
    width: 100%;
    margin: .15rem 0 0;
    padding: .35rem 0 0;
    border-top: 1px solid var(--rule);
  }
  .card-face-nav__label {
    /* aria-label="Card view" on the group carries the name; the visible
       "View cards as" row cost a full line of mobile chrome (2026-08-11). */
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .card-face-nav__button {
    min-width: 0;
    /* 32px -> 36px, cap .65rem -> .72rem (operator 2026-08-21, mobile
       copy-density audit: ~9.9px inside a 32px button was too small).
       Lower regression risk than the jump-nav's cap above -- this rule
       already carries overflow:hidden + text-overflow:ellipsis as a
       designed fallback, so a label that doesn't fit degrades to "…"
       instead of wrapping/breaking layout. */
    min-height: 36px;
    padding: 4px 2px;
    overflow: hidden;
    font-size: clamp(.55rem, 2.55vw, .72rem);
    text-overflow: ellipsis;
  }
}


/* ---- Closed dimension: section separation (operator 2026-08-14) ----------
   Closed carries two members that make DIFFERENT claims about a named
   business: "Confirmed closed" rests on a public record, while "Licence
   lapsed" is a regulatory state and explicitly not a closure. A reader
   scrolling past a faint hairline can carry the first heading's meaning into
   the second list, which is precisely the misreading that matters here. So
   this divider is a boundary, not a caption: full-weight rule in the group
   accent, and real space above it. */
.dimension--group-closed .dim-divider {
  margin: 1.75rem 0 .6rem;
  padding-bottom: .4rem;
  border-bottom: 2px solid var(--face-ink, #3f3f46);
}
.dimension--group-closed .dim-divider:first-of-type { margin-top: .4rem; }
.dimension--group-closed .dim-divider__label {
  color: var(--face-ink, #3f3f46);
  font-size: .82rem;
  letter-spacing: .1em;
}


/* ---- Desktop nav: two rows, not one scrolling strip (operator 2026-08-14) --
   .jump-nav is flex-wrap:nowrap + overflow-x:auto so a long nav scrolls
   sideways. For the DIMENSION tabs that is the wrong model: the group tabs and
   the card-face ("view cards as") controls are two different kinds of choice,
   and side-by-side on one scrolling line they read as one undifferentiated
   strip -- with the view modes liable to sit off-screen entirely. Allowing the
   tab nav to wrap lets .card-face-nav's existing flex:0 0 100% do what it
   always intended: take its own row. Scoped to --tabs so every other jump-nav
   keeps its scrolling behaviour. */
@media (min-width: 768px) {
  .jump-nav.jump-nav--tabs {
    /* !important is required, not decorative: "MED #6" above pins
       .jump-nav to flex-wrap:nowrap !important + overflow-x:auto !important
       at >=1024px, which is why this looked fixed at 768 and stayed broken on
       an actual desktop. That rule is right for the other jump-navs -- a long
       link list should scroll -- so this overrides it only for --tabs, where
       specificity (0,2,0) beats (0,1,0) once both are !important. */
    flex-wrap: wrap !important;
    overflow-x: visible !important;
    row-gap: var(--s-1);
  }
}

/* SHARE FIGURES (operator 2026-08-15). The metro card on the lazy-load
   preview and the three "What's risky right now" cards are the SAME SVG that
   gets shared, rendered inline rather than described by a tile. One artefact,
   so what a reader sees and what they post cannot drift apart.

   The SVG carries width="1200" height="630" for the canvas rasteriser, which
   would otherwise force a 1200px-wide box; the viewBox lets it scale, so the
   width/height are overridden here and the aspect ratio is held by the
   viewBox itself. Without the `display:block` the inline-baseline gap shows
   as a hairline of page background under every card. */
.share-figure { margin: 0; }
/* No .share-figure__svg rule any more: the page never inlines a share card.
   The graphic is rasterised from the payload at share time and handed to the
   share sheet, so it is never laid out by CSS at all. */
.share-figure__link {
  display: block;
  text-decoration: none;
  border-radius: .5rem;
}
.share-figure__link:focus-visible {
  outline: 3px solid var(--focus-ring-color, #0f172a);
  outline-offset: 3px;
}
.share-figure__cap {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--s-2);
}
/* Three 1.9:1 cards side by side would be unreadable on a laptop, so they
   wrap on their own content width rather than being forced into a 3-up row. */
/* FOUR CARDS, NEVER THREE ACROSS (operator 2026-08-16: "uneven staggering of
   the What's Risky cards in desktop browser view").

   auto-fit with a 340px floor picks whatever column count fits, and on a
   typical desktop that is THREE -- which leaves the fourth card alone on a
   second row with two empty cells beside it. The rail always renders exactly
   HERO_CARD_COUNT = 4 tiles, so the column count is pinned to divisors of 4:
   1, then 2, then 4. Every layout is complete; none can orphan a card.

   The second half of "uneven" is height. .share-text is the visible box and
   sized itself to its own text, so cards in the same row ended at different
   depths -- a venue with a one-line finding sat noticeably short next to one
   with three. Grid stretches the FIGURE, but the box inside it stopped at its
   content, so the chain has to be told to fill. */
.hero-rail__tiles--cards {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-3);
  align-items: stretch;
}
@media (min-width: 720px) {
  .hero-rail__tiles--cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1400px) {
  .hero-rail__tiles--cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* THE WRAPPER IN THE MIDDLE IS PART OF THE CHAIN (operator 2026-08-17: the
   cards still did not match).

   The tile is figure > .share-figure__text > .share-text, and the visible box
   is the INNERMOST one. `height: 100%` was set on .share-text while
   .share-figure__text kept its auto height -- and a percentage height against
   an auto-height parent is IGNORED, so the box quietly sized to its own text
   and the four cards ended at four different depths while their Share buttons
   lined up underneath.

   Height percentages need a definite parent at every step, which is why this
   uses flex instead: the figure is a column, the text wrapper takes the space
   the figcaption does not, and the dark box fills that. No step can silently
   opt out. */
.share-figure--hero {
  display: flex;
  flex-direction: column;
  height: 100%;
}
/* THE LINK WRAPPER WAS THE MISSING LINK (operator 2026-08-17: "the share
   buttons appear to be obscured by the metro closure text cards").

   The chain comment above says "figure > .share-figure__text > .share-text",
   and it is wrong -- the real DOM is figure > a.share-figure__link >
   .share-figure__text > .share-text. The base .share-figure__link rule is
   `display: block`, so as a flex item of the .share-figure--hero column it
   defaults to flex:0 1 auto with an implicit min-height:auto (the same trap
   the chain below was fixed for). It cannot shrink below its own content's
   height, so a card with enough text grows past the figure's fixed
   height:100% -- unclipped, since nothing here sets overflow:hidden -- and
   spills into the figcaption below it, or into the row of cards beneath it
   in the grid, covering their Share buttons.

   And .share-figure__text's OWN flex:1 1 auto (below) was never taking
   effect either: flex properties only apply to a DIRECT child of a flex
   container, and its actual parent (.share-figure__link) was not one. Making
   the link itself a flex column closes both gaps at once. */
.share-figure--hero .share-figure__link {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.share-figure--hero .share-figure__text {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
}
.share-figure--hero .share-text {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  min-height: 0;
}
/* BUFFER SPACE, SO EVERY CARD IS THE SAME SIZE (operator 2026-08-16: "they
   need to be built so buffer space exists for the text so the cards come out
   all the same size").

   Three things were still uneven after the boxes were stretched:

   1. GRID ROWS SIZED INDEPENDENTLY. At the 2-column width the rail is a 2x2,
      and each row took the height of its own tallest card -- so the two cards
      on top could be visibly shorter than the two below. `grid-auto-rows: 1fr`
      makes every row the same height, which is what makes all FOUR cards match
      rather than matching only their row-mate.

   2. OPTIONAL LINES COLLAPSED. A venue with no city, no resolved dates or no
      inspector narrative rendered a shorter card. The rows are now always
      emitted (see shareAlertTextHtml) and reserve their height here when empty,
      so the eyebrow, headline, stat and findings share baselines across cards.

   3. ONE LONG FINDING STRETCHED ALL FOUR. Because the rows are equal, the
      tallest note set the height of every card. The note is capped at four
      lines; past that it ellipsises, and the full text is on the venue's own
      record where there is room for it. */
.hero-rail__tiles--cards { grid-auto-rows: 1fr; }
.share-figure--hero .share-text__sub { min-height: 1.2em; }
.share-figure--hero .share-text__label { min-height: 1.1em; }
.share-figure--hero .share-text__note {
  /* The variable-length part takes the slack, so the headline, location and
     dates above it stay on a common baseline across all four cards. */
  margin-bottom: auto;
  display: -webkit-box;
  /* 4 -> 7 lines (operator 2026-08-17: the finding was "cut off").

     This row carries inspectionSummary().full, the same receipt the
     Overview/Alert face shows. Measured on the live corpus it runs 149-240
     chars; in a quarter-width rail tile at .85rem that is ~44 chars a line,
     so 240 chars needs ~6 lines and a 4-line clamp truncated the majority of
     them mid-sentence -- on the one row whose whole job is to say what
     inspectors found. 7 lines clears the 240-char cap (the hard ellipsis in
     inspectionSummary) with a line to spare.

     min-height stays at 4 lines: it reserves space for a SHORT note so the
     rows above stay on a common baseline, while the clamp bounds a long one.
     Raising it too would pad every card to the tallest possible note. */
  -webkit-line-clamp: 7;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 4.8em;
}
/* An empty row reserves space without inventing content: no text, no bullet,
   nothing for a screen reader to announce. */
.share-figure--hero .share-text__sub--empty,
.share-figure--hero .share-text__label--empty,
.share-figure--hero .share-text__note--empty { visibility: hidden; }

/* MOBILE: THE SAME CARD, AS TEXT (operator 2026-08-15).

   A 1200x630 graphic is a desktop object. In a phone column the roster's
   9-13pt type lands under 5pt and naming the venues -- the entire point of
   the card -- stops working. That is why the rail was hidden on mobile
   originally; hiding it also removed the share button, which is backwards,
   since sharing is overwhelmingly a phone action.

   So the SVG and a text rendering of the SAME facts are both emitted and CSS
   picks one. The share button is outside the swap and works in both: the
   handler builds its own SVG from the payload rather than lifting the one on
   screen, so the image that reaches Facebook is identical either way. */
/* THE TEXT IS THE PAGE VERSION AT EVERY WIDTH (operator 2026-08-16: "use
   the text summary version of the share card summaries on desktop also, only
   use the share card graphic during a share operation"). It was desktop-SVG /
   mobile-text; the SVG is now built only when somebody shares. */
.share-figure__text { display: block; }
/* THE TEXT BOX IS THE CARD, IN TEXT (operator 2026-08-15: "for the text
   based boxes I would use the same color scheme as the graphics").

   The mobile view stood on the page's white ground in site colours while the
   thing it substitutes for is a near-black card with a red alert block. A
   reader who saw the graphic on a laptop and the text on a phone had no cue
   they were the same object, and the share button beneath it produces the
   graphic either way. These are the card's own tokens, literal rather than
   themed, for the same reason the SVG's are: this panel is a rendering of an
   artefact that has one fixed appearance wherever it travels. */
/* COMPACT (operator 2026-08-16: "scale the share card summary so it takes up
   less space"). Four of these stack in the rail, so the padding, the headline
   and the block around the count are all a step down from the standalone
   panel this started as. */
.share-text {
  background: #0b0b0d;
  color: #f7f4ef;
  border-radius: .5rem;
  padding: .6rem .7rem;
  border-top: 4px solid #c62828;
}
.share-text__eyebrow {
  margin: 0 0 .15rem;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3, #64748b);
}
.share-text__eyebrow { color: #9a938a; }
.share-text__eyebrow--alert { color: #ff5f52; }
.share-text__headline {
  margin: 0 0 .15rem;
  font-size: clamp(1.15rem, .75rem + 1.1vw, 1.4rem);
  font-weight: 800;
  line-height: 1.25;
  color: #f7f4ef;
}
.share-text__headline strong { font-size: 1.35rem; }
.share-text__sub,
.share-text__note { margin: 0 0 .35rem; font-size: .85rem; color: #9a938a; }
.share-text__sub--dates { font-weight: 600; }
/* The count sits in the card's alert red, the way the filled block does --
   it is the one number the card exists to carry. */
.share-text__stat {
  margin: .25rem 0 .1rem;
  padding: .25rem .45rem;
  border-radius: .35rem;
  background: #c62828;
  color: #fff;
  font-size: .95rem;
  font-weight: 700;
}
.share-text__stat strong { font-size: 1.15rem; }
.share-text__stat--none { background: #7f1d1d; font-weight: 600; }
.share-text__rest { font-weight: 400; opacity: .9; }
.share-text__label {
  margin: .5rem 0 .25rem;
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.share-text__label--shut { color: #ff5f52; }
.share-text__label--remediation { color: #67d9cf; }
.share-text__label--reopened { color: #ffc93c; }
/* Defensive only: at a real 366px column every name in the live roster
   wraps correctly on its own, including "PALOMINO GARDENS RETIREMENT LLC".
   These bound the case the data has not produced yet -- a single name longer
   than the column, which as a flex item would otherwise refuse to shrink
   below its content (min-width defaults to auto) and push the row past the
   viewport.

   Recorded because the first version of this comment claimed to fix an
   overflow that had been OBSERVED. It had not: chromium's --window-size does
   not drive the layout viewport in this build, so the "mobile" screenshots
   were desktop-width renders cropped to 390px. Verified with a fixed
   right-anchored probe that never appeared in frame, then re-checked inside
   an explicit 366px column, which is what the shot above shows. */
.share-text__list {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}
.share-text__chip {
  padding: .15rem .5rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 700;
  border: 1px solid currentColor;
  max-width: 100%;
  min-width: 0;
  overflow-wrap: anywhere;
}
.share-text__chip--shut { color: #ff5f52; }
.share-text__chip--remediation { color: #67d9cf; }
.share-text__chip--reopened { color: #ffc93c; }

@media (max-width: 767px) {
  .hero-rail__tiles--cards { grid-template-columns: 1fr; gap: var(--s-2); }
  .share-figure__cap { justify-content: stretch; }
  .share-figure__cap .share-card__btn { flex: 1; }
}

/* DOSSIER: the card's link to its full corpus entry (operator 2026-08-15).
   Sized as a thumb target because it sits in the card action row, which on a
   phone is the densest cluster of controls on the page. */
.card__action-btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 6px 14px;
  border: 1px solid var(--ink-1, #1a1a1a);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-1, #1a1a1a);
  font-weight: 700;
  font-size: var(--text-sm);
  text-decoration: none;
}
.card__action-btn:hover { background: var(--ink-1, #1a1a1a); color: var(--paper); }
.card__action-btn:focus-visible {
  outline: 3px solid var(--focus-ring-color, #0f172a);
  outline-offset: 2px;
}

/* The dossier link sits in the card header so it is reachable from every
   face (operator 2026-08-15). Right-aligned on wide cards so it does not
   compete with the venue name for the first read, full-width on a phone
   where it is a primary action rather than an afterthought. */
.card__head .card__action-btn {
  align-self: flex-start;
  margin-top: var(--s-2);
}
@media (max-width: 767px) {
  .card__head .card__action-btn { width: 100%; justify-content: center; }
}
/* The window rides with the metro name, muted, the way it sits top-right on
   the graphic. */
.share-text__window { font-weight: 600; letter-spacing: 0; color: #9a938a; }

/* THE EVIDENCE LEDGER (operator 2026-08-17). A closure claim on a named
   business needs its reasoning visible, not just its verdict. The caveat text
   is deliberately not muted into invisibility: "an ACTIVE licence proves
   nothing" is the single most important line on the card for a reader who would
   otherwise read Active as open. */
.card__details--ledger { margin-top: var(--s-2); }
.ledger {
  width: 100%;
  border-collapse: collapse;
  font-size: clamp(.82rem, .95vw, .95rem);
}
.ledger th,
.ledger td {
  text-align: left;
  vertical-align: top;
  padding: 6px 8px;
  border-bottom: 1px solid var(--rule, #e5e7eb);
}
.ledger th {
  width: 11em;
  font-weight: 700;
  color: var(--ink, #1f2937);
  white-space: nowrap;
}
.ledger td { color: var(--ink, #1f2937); overflow-wrap: anywhere; }
.ledger tr:last-child th,
.ledger tr:last-child td { border-bottom: 0; }
/* The caveat is the point of the row, so it reads as prose rather than as a
   footnote nobody finishes. */
.ledger__caveat {
  display: block;
  margin-top: 2px;
  color: var(--ink-muted, #57534e);
  font-style: italic;
}
@media (max-width: 640px) {
  /* Stack: an 11em label column plus wrapped findings is unreadable at 340px. */
  .ledger th, .ledger td { display: block; width: auto; white-space: normal; }
  .ledger th { padding-bottom: 0; border-bottom: 0; }
  .ledger td { padding-top: 2px; }
}

/* ---- Maximum Enforcement on a dimension card -----------------------------
   The strongest label the site applies, so it renders ABOVE the Megaviolator
   row it sits beside and carries the chronic-register maroon. Kept to a stat
   row rather than a badge because the claim is arithmetic ("ordered shut N
   times") and a badge cannot show its own evidence. */
.card__stat--maxenf {
  border-left: 3px solid var(--red-deep);
  padding-left: var(--s-2);
  margin-top: var(--s-2);
}
.card__stat--maxenf dt {
  color: var(--red-deep);
  font-weight: 800;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.card__stat--maxenf dd { color: var(--ink); font-variant-numeric: tabular-nums; }
