/* ════════════════════════════════════════════════════════════════════════════
   CCWP public component library (SPEC §3.3) — consumed by every public page
   (county, elections, plats, jobs, meetings, Document Center).

   RULES OF THIS FILE
   - Every color comes from tokens.css custom properties. Zero raw hex here.
   - Exactly four breakpoints: 480 / 768 / 1024 / 1280 (see tokens.css).
   - No `overflow-x: hidden` band-aids; no 100vw breakout tricks.
   - Body/UI text never drops below 1rem (kickers/badges use --fs-meta 15px
     uppercase, which is label typography, not body text).
   - Focus rings are never removed; :focus-visible is styled everywhere.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 1. Base ────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--fs-0);
  line-height: var(--lh-body);
  color: var(--color-text);
  background: var(--color-surface);
  text-rendering: optimizeLegibility;
}

img, svg, video { max-width: 100%; height: auto; }
img { border-style: none; }

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  line-height: var(--lh-tight);
  color: var(--color-heading);
  margin: 0 0 var(--space-4);
}
h1 { font-size: var(--fs-5); }
h2 { font-size: var(--fs-4); }
h3 { font-size: var(--fs-3); font-weight: var(--fw-bold); }
h4, h5, h6 { font-size: var(--fs-2); font-weight: var(--fw-bold); }

p { margin: 0 0 var(--space-4); }

a { color: var(--color-link); text-decoration-thickness: 1px; text-underline-offset: 0.15em; }
a:hover { color: var(--color-link-hover); }

/* Links in prose stay underlined (WCAG 1.4.1 — color is never the only cue) */
nav a, .btn, .card a, .task-chip, .hero-chip, .quicklink-row, .doc-link,
.section-head__more, .site-brand, .social-disc,
.news-card__title a, .event-row__title a { text-decoration: none; }
.news-card__title a:hover, .event-row__title a:hover { text-decoration: underline; }
.prose a, main p a, main li a, .page-banner__lede a,
main a[href^="tel:"], main a[href^="mailto:"] { text-decoration: underline; }
/* Prose inside .card must stay underlined too — .card a (0,1,1) otherwise
   out-specifies main p a (0,0,3) and leaves color-only links (axe
   link-in-text-block, WCAG 1.4.1). Card-title/whole-card links are not
   inside <p>/<li>, so their styling is unchanged. */
.card p a, .card li a { text-decoration: underline; }
.prose a:hover, main p a:hover { text-decoration-thickness: 2px; }

hr { border: 0; border-top: 1px solid var(--color-border); margin: var(--space-6) 0; }

::selection { background: var(--cc-navy); color: var(--color-text-invert); }

/* ── 2. Focus (WCAG 2.4.7 — ring never removed) ─────────────────────────── */

:focus { outline: none; }
:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}
.utility-bar :focus-visible, .site-header :focus-visible,
.primary-nav :focus-visible, .site-footer :focus-visible,
.hero :focus-visible, .band-navy :focus-visible,
.alert-bar--urgent :focus-visible, .alert-bar--closure :focus-visible,
.mobile-menu__button:focus-visible {
  box-shadow: var(--focus-ring-dark);
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  box-shadow: 0 0 0 3px var(--gold-alpha-25), 0 0 0 1px var(--cc-navy);
  border-color: var(--cc-navy);
}

/* ── 3. Utilities ───────────────────────────────────────────────────────── */

.container {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.visually-hidden, .sr-only {
  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: -100vh; left: var(--space-2);
  z-index: 200;
  background: var(--cc-navy-dark);
  color: var(--color-text-invert);
  font-weight: var(--fw-bold);
  padding: var(--space-3) var(--space-5);
  border-radius: 0 0 var(--radius) var(--radius);
}
.skip-link:focus, .skip-link:focus-visible {
  top: 0;
  color: var(--color-text-invert);
  box-shadow: var(--focus-ring-dark);
}

.icon {
  width: 1.25em; height: 1.25em;
  vertical-align: -0.25em;
  flex: none;
}

.kicker {
  font-size: var(--fs-meta);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cc-gold-text);
  margin: 0 0 var(--space-2);
}

/* Merriweather section headings with the gold rule accent */
.has-rule {
  position: relative;
  padding-bottom: var(--space-3);
}
.has-rule::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 3.5rem; height: 3px;
  background: var(--cc-gold);
  border-radius: var(--radius-full);
}

.empty-note {
  color: var(--color-text-muted);
  background: var(--color-surface-tint);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
}

/* ── 4. Utility bar ─────────────────────────────────────────────────────── */

.utility-bar {
  background: var(--cc-navy-dark);
  color: var(--color-text-invert);
}
.utility-bar__inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  padding-block: var(--space-2);
}
.utility-bar p { margin: 0; }
.utility-bar__contact {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-2) var(--space-4);
}
.utility-bar a { color: var(--color-text-invert); }
.utility-bar a:hover { color: var(--cc-gold-bright); }
.utility-bar .icon { color: var(--cc-gold-bright); margin-right: var(--space-1); }
.utility-bar__links {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--space-2) var(--space-4);
}
.utility-bar__espanol {
  background: var(--cc-gold-bright);
  color: var(--cc-navy-dark);              /* 5.4:1 on gold-bright ✓ */
  font-weight: var(--fw-semibold);
  border-radius: var(--radius-full);
  padding: 0 var(--space-3);
}
@media (min-width: 768px) {
  .utility-bar__inner { justify-content: space-between; }
}

/* ── 5. Sticky header ───────────────────────────────────────────────────── */

.header-sticky {
  position: sticky;
  top: 0;
  z-index: 100;
  box-shadow: var(--shadow-2);
}

.site-header {
  background: var(--grad-header);
  border-bottom: 3px solid var(--cc-gold);
  color: var(--color-text-invert);
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-3);
}

.site-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-text-invert);
  min-width: 0;
}
.site-brand__seal {
  width: 56px; height: 56px;
  filter: drop-shadow(0 2px 4px var(--shadow-color-deep));
  transition: transform var(--transition);
}
.site-brand:hover .site-brand__seal { transform: scale(1.04); }
.site-brand__text { display: flex; flex-direction: column; min-width: 0; }
.site-brand__name {
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-2);
  line-height: var(--lh-tight);
  color: var(--color-text-invert);
}
.site-brand__tagline {
  font-family: var(--font-display);
  font-style: italic;
  font-size: var(--fs-meta);
  color: var(--cc-gold-light);             /* on header gradient ≥ 9.4:1 ✓ */
}
@media (min-width: 768px) {
  .site-brand__seal { width: 72px; height: 72px; }
}

.header-search {
  display: none;
  align-items: center;
  gap: var(--space-2);
}
.header-search input {
  width: 240px;
  background: var(--white-alpha-18);
  border: 1px solid var(--white-alpha-35);
  border-radius: var(--radius-full);
  color: var(--color-text-invert);
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-0);
  transition: background var(--transition), border-color var(--transition);
}
.header-search input::placeholder { color: var(--white-alpha-70); }
.header-search input:focus { background: var(--white-alpha-10); border-color: var(--cc-gold-bright); }
.header-search__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--grad-gold-btn);
  color: var(--cc-navy-dark);              /* on gold 4.7:1+ ✓ */
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition);
}
.header-search__btn:hover { transform: scale(1.05); box-shadow: var(--shadow-2); }
@media (min-width: 1024px) {
  .header-search { display: flex; }
}

/* ── 6. Primary nav + mega panels ───────────────────────────────────────── */

.nav-row {
  position: relative;
  background: var(--cc-navy-mid);
  display: flex;
  align-items: stretch;
  justify-content: space-between;
}

.primary-nav { display: none; flex: 1; }
@media (min-width: 1024px) {
  .primary-nav { display: block; }
}
.primary-nav__list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
}
.nav-item { position: static; }
.nav-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--color-text-invert);         /* on navy-mid 8.1:1 ✓ */
  font-weight: var(--fw-medium);
  font-size: var(--fs-0);
  padding: var(--space-3) var(--space-4);
  border-bottom: 3px solid transparent;
  transition: background var(--transition), border-color var(--transition);
}
.nav-link:hover, .nav-item.is-open .nav-link {
  background: var(--cc-navy);
  color: var(--cc-gold-light);             /* on navy 9.4:1 ✓ */
}
.nav-link.is-active, .nav-link[aria-current] {
  border-bottom-color: var(--cc-gold-bright);
}
.nav-link__chevron { width: 1em; height: 1em; opacity: 0.75; }
.js .nav-link__chevron { display: none; }  /* the real toggle button takes over */
.nav-toggle {
  border: 0;
  background: transparent;
  color: var(--color-text-invert);
  padding: 0 var(--space-2);
  cursor: pointer;
}
.nav-toggle .icon { transition: transform var(--transition); }
.nav-toggle[aria-expanded="true"] .icon { transform: rotate(180deg); }

/* Panels — no-JS fallback: open on hover/:focus-within (fully keyboard-
   reachable); top-level links navigate to their hub pages. When public.js
   runs (html.js) the pure-CSS behavior is disabled and .is-open (managed by
   JS: click, hover-intent, Escape, outside-click, aria-expanded) is the ONLY
   open state, so state can never disagree with the ARIA. */
.mega-panel {
  display: none;
  position: absolute;
  left: 0; right: 0;
  top: 100%;
  background: var(--color-surface);
  border-top: 3px solid var(--cc-gold);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-3);
  z-index: 90;
}
.nav-item:hover .mega-panel,
.nav-item:focus-within .mega-panel,
.nav-item.is-open .mega-panel { display: block; }
.js .nav-item:not(.is-open):hover .mega-panel,
.js .nav-item:not(.is-open):focus-within .mega-panel { display: none; }

.mega-panel__inner {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) 3fr;
  gap: var(--space-6);
  padding-block: var(--space-6);
}
.mega-panel__desc {
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
}
.mega-panel__featured {
  display: block;
  position: relative;
  background: var(--cc-navy);
  color: var(--color-text-invert);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  box-shadow: var(--shadow-2);
  transition: transform var(--transition), box-shadow var(--transition);
}
.mega-panel__featured:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); color: var(--color-text-invert); }
.mega-panel__featured .kicker { color: var(--cc-gold-bright); }
.mega-panel__featured-label {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: var(--fs-2);
  margin-bottom: var(--space-1);
}
.mega-panel__featured-desc { display: block; color: var(--cc-navy-light); }
.mega-panel__featured-arrow { position: absolute; right: var(--space-4); bottom: var(--space-4); color: var(--cc-gold-bright); }

.mega-panel__links {
  list-style: none;
  margin: 0; padding: 0;
  columns: 2;
  column-gap: var(--space-6);
}
@media (min-width: 1280px) {
  .mega-panel__links { columns: 3; }
}
.mega-panel__links li { break-inside: avoid; margin-bottom: var(--space-2); }
.mega-panel__links a {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-link);
}
.mega-panel__links a:hover { background: var(--cc-navy-light); color: var(--cc-navy); }
.mega-link__label { display: block; font-weight: var(--fw-semibold); }
.mega-link__desc { display: block; color: var(--color-text-muted); }

/* Elections compact nav: same bar, no panels */
.primary-nav--compact .nav-link { font-size: var(--fs-0); }

/* ── 7. Mobile menu (native <details> sheet WITH search) ────────────────── */

.mobile-menu { display: block; }
@media (min-width: 1024px) {
  .mobile-menu { display: none; }
}
.mobile-menu__button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  cursor: pointer;
  color: var(--color-text-invert);
  font-weight: var(--fw-semibold);
  padding: var(--space-3) var(--space-4);
  min-height: 48px;
}
.mobile-menu__button::-webkit-details-marker { display: none; }
.mobile-menu__close-icon { display: none; }
.mobile-menu[open] .mobile-menu__close-icon { display: inline; }
.mobile-menu[open] .mobile-menu__open-icon { display: none; }

.mobile-menu__sheet {
  position: fixed;
  inset: 0;
  top: var(--mobile-sheet-top, 0);
  z-index: 150;
  background: var(--color-surface);
  overflow-y: auto;
  padding: var(--space-5) var(--container-pad) var(--space-10);
  box-shadow: var(--shadow-4);
}
.mobile-menu__search {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}
.mobile-menu__search input {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-0);
}
.mobile-menu__list {
  list-style: none;
  margin: 0; padding: 0;
}
.mobile-menu__list > li { border-bottom: 1px solid var(--color-border); }
.mobile-menu__link,
.mobile-menu__group summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-2);
  font-weight: var(--fw-semibold);
  color: var(--cc-navy);
  cursor: pointer;
  min-height: 48px;
}
.mobile-menu__group summary { list-style: none; }
.mobile-menu__group summary::-webkit-details-marker { display: none; }
.mobile-menu__group summary .icon { transition: transform var(--transition); color: var(--cc-gold-text); }
.mobile-menu__group[open] > summary .icon { transform: rotate(180deg); }
.mobile-menu__group ul {
  list-style: none;
  margin: 0; padding: 0 0 var(--space-3) var(--space-4);
}
.mobile-menu__group ul a {
  display: block;
  padding: var(--space-2);
  color: var(--color-link);
  border-radius: var(--radius-sm);
}
.mobile-menu__group ul a:hover { background: var(--cc-navy-light); }

/* ── 8. Alert bars ──────────────────────────────────────────────────────── */

.alert-bar { border-bottom: 1px solid var(--white-alpha-18); }
.alert-bar__inner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block: var(--space-3);
}
.alert-bar__text { margin: 0; flex: 1; }
.alert-bar__icon .icon { width: 1.4em; height: 1.4em; }
.alert-bar__dismiss {
  border: 0;
  background: transparent;
  color: inherit;
  cursor: pointer;
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  min-width: 36px; min-height: 36px;
}
.alert-bar__dismiss:hover { background: var(--white-alpha-18); }
.alert-bar a { color: inherit; text-decoration: underline; font-weight: var(--fw-semibold); }

.alert-bar--info    { background: var(--alert-info-bg);    color: var(--alert-info-fg); }
.alert-bar--warning { background: var(--alert-warning-bg); color: var(--alert-warning-fg); }
.alert-bar--warning .alert-bar__icon { color: var(--alert-warning-accent); }
.alert-bar--urgent  { background: var(--alert-urgent-bg);  color: var(--alert-urgent-fg); }
.alert-bar--success { background: var(--alert-success-bg); color: var(--alert-success-fg); }
.alert-bar--closure { background: var(--alert-closure-bg); color: var(--alert-closure-fg); }
.alert-bar--closure .alert-bar__icon { color: var(--alert-closure-accent); }
.alert-bar--warning .alert-bar__dismiss:hover,
.alert-bar--info .alert-bar__dismiss:hover,
.alert-bar--success .alert-bar__dismiss:hover { background: var(--navy-alpha-15); }

/* ── 9. Page banner (breadcrumbs + single thin gold/red stripe) ─────────── */

.page-banner {
  position: relative;
  background:
    var(--scrim-navy-grad),
    var(--img-courthouse-banner) center 30% / cover no-repeat,
    var(--cc-navy-dark);
  color: var(--color-text-invert);
}
.page-banner::after {          /* the flag stripe — used ONCE per page */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 4px;
  background: linear-gradient(180deg, var(--cc-gold) 0 62%, var(--cc-red) 62% 100%);
}
.page-banner__inner { padding-block: var(--space-7) var(--space-8); }
.page-banner__title {
  color: var(--color-text-invert);
  font-size: var(--fs-5);
  margin: 0;
  text-wrap: balance;
}
.page-banner__lede {
  margin: var(--space-3) 0 0;
  max-width: 46rem;
  font-size: var(--fs-1);
}

/* ── the department contact card, inside the banner ────────────────────────
   Who runs this department, what to ring, when they are open — lifted out of a
   card partway down the page and put where a resident looks first.

   GLASS. Three layers do the work, in this order: a top-down white sheen that
   gives the pane its lit edge, a navy body that supplies the contrast, and a
   blur+saturate behind the whole thing so the courthouse reads through as
   colour rather than detail. The 1px inset highlight along the top is what
   makes it look like a pane with thickness instead of a flat translucent box.

   The navy stays dominant on purpose. The banner is already a navy scrim over
   a photograph, so a panel that DARKENS can only make the white type more
   legible than the H1 above it, whatever the picture does underneath; a panel
   that lightened would put contrast at the mercy of the image. Measured
   against the worst case — the scrim over bright sky — this is 8:1 or better.
   The sheen is kept low for exactly that reason. */
.banner-contact {
  --glass-body: rgba(9, 42, 29, .52);
  margin: var(--space-5) 0 0;
  padding: var(--space-4) var(--space-5);
  max-width: 46rem;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  border-radius: 14px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .10) 0%, rgba(255, 255, 255, .02) 55%, rgba(255, 255, 255, 0) 100%),
    var(--glass-body);
  border: 1px solid rgba(255, 255, 255, .26);
  box-shadow:
    0 10px 30px rgba(4, 20, 14, .34),
    inset 0 1px 0 rgba(255, 255, 255, .40);
  backdrop-filter: blur(14px) saturate(135%);
  -webkit-backdrop-filter: blur(14px) saturate(135%);
}
.banner-contact__seal {
  flex: none;
  width: 64px;
  height: 64px;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, .45));
}
.banner-contact__body { min-width: 0; }

/* Type: the person is the headline, the office is the caption under it. Both
   were one size before, which is why the card read as an undifferentiated run
   of words. */
.banner-contact__who { margin: 0 0 var(--space-3); display: flex; flex-direction: column; gap: 1px; }
.banner-contact__name {
  font-size: var(--fs-2);
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-text-invert);
}
.banner-contact__role { font-size: var(--fs-meta); color: var(--cc-navy-light); }

.banner-contact__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  font-size: var(--fs-0);
}
.banner-contact__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-invert);
  line-height: 1.45;
}
.banner-contact__item svg { flex: none; width: 17px; height: 17px; opacity: .8; }
.banner-contact__value { min-width: 0; overflow-wrap: anywhere; }
/* Underlined, so the link is never carried by colour alone against a photo. */
.banner-contact a { color: var(--color-text-invert); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.banner-contact a:hover { text-decoration-thickness: 2px; }
.banner-contact a:focus-visible { outline: 2px solid var(--cc-gold); outline-offset: 3px; border-radius: 3px; }

@media (max-width: 480px) {
  /* One item per line on a phone: a wrapped row of four reads as a paragraph
     of unrelated fragments. The seal shrinks rather than wrapping away — it is
     what identifies the card at a glance. 480px is the system's small
     breakpoint; the four in SPEC are 480/768/1024/1280 and renderer.test.js
     enforces exactly those. */
  .banner-contact { padding: var(--space-4); gap: var(--space-3); align-items: flex-start; }
  .banner-contact__seal { width: 48px; height: 48px; }
  .banner-contact__list { flex-direction: column; gap: var(--space-2); }
}
@media (prefers-reduced-transparency: reduce) {
  /* No blur, no sheen — the flat navy already carries every contrast figure. */
  .banner-contact {
    background: var(--cc-navy-dark);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}
/* The pale-blue lede tint is validated against the navy banner ONLY — scope
   it there so a stray use on the white page body inherits dark text instead
   of rendering 1.15:1 (axe color-contrast blocker on the jobs pages). */
.page-banner .page-banner__lede { color: var(--cc-navy-light); }
/* Lede paragraph for white page-body content (jobs summary): muted gray-600
   on white is a pre-validated 7.0:1 pairing (tokens.css). */
.page-lede {
  margin: var(--space-5) 0 var(--space-4);
  max-width: 46rem;
  font-size: var(--fs-1);
  color: var(--color-text-muted);
}

.breadcrumbs { margin-bottom: var(--space-4); }
.breadcrumbs ol {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-0);
}
.breadcrumbs li { display: flex; align-items: center; gap: var(--space-1); }
.breadcrumbs li + li::before {
  content: "/";
  color: var(--cc-gold-bright);
  margin-inline: var(--space-1);
}
.breadcrumbs a { color: var(--cc-navy-light); }
.breadcrumbs a:hover { color: var(--color-text-invert); }
.breadcrumbs [aria-current="page"] { color: var(--color-text-invert); font-weight: var(--fw-semibold); }

.page-plain-head { padding-top: var(--space-6); }

/* ── 10. Page content column ────────────────────────────────────────────── */

main { display: block; }
.page-content { padding-block: var(--space-6) var(--space-10); }
.page-content > .block {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
.page-content > .block + .block { margin-top: var(--space-6); }
.page-content > .block--full {
  max-width: none;
  padding-inline: 0;
}
.page-content > .block-hero-banner:first-child { margin-top: calc(-1 * var(--space-6)); }
/* Imported legacy html blocks (admin escape hatch): long unbroken tokens
   (emails, URLs) wrap instead of forcing 320 px page overflow, and media
   never exceeds the column. Scoped to .block-html so designed blocks keep
   their own rules. overflow-wrap inherits into the legacy markup. */
.block-html { overflow-wrap: anywhere; }
.block-html img, .block-html figure, .block-html iframe, .block-html video { max-width: 100%; height: auto; }
.block-html figure { margin-inline: 0; }
/* Legacy .site design-token aliases for imported html blocks. The migrated
   vendor/.site markup references custom properties from the OLD stylesheet;
   an unresolved var() falls back to transparent/inherit, which produced
   white-on-white buttons/badges and invisible text on published pages
   (real WCAG 1.4.3 failures). Each alias maps to the nearest token that is
   ACCESSIBLE in the position the legacy content uses it. Remove alongside
   the SPEC §13.4 html-block cleanup pass. */
.block-html {
  --cc-blue: var(--cc-navy-mid);
  --cc-blue-mid: var(--cc-navy-mid);
  --cc-blue-light: var(--cc-navy-light);
  --cc-gold: var(--cc-gold-text);      /* legacy gold TEXT sits on white */
  --cc-gray: var(--cc-gray-100);      /* legacy uses it ONLY as a light wash bg */
  --cc-gray-mid: var(--cc-gray-300);  /* legacy border gray */
  --cc-text-light: var(--color-text-muted);
  --text-light: var(--color-text-muted);
  --text-muted: var(--color-text-muted);
  --em-red: var(--cc-red);
  --em-red-light: var(--cc-red-light);
  --shadow: var(--shadow-1);
}
/* Links in legacy prose must not rely on color alone (WCAG 1.4.1) — the
   legacy stylesheet underlined them; imported markup depends on that. */
.block-html a:not(.btn) { text-decoration: underline; }
/* Legacy navy hero panels (sheriff crime-prevention set): restore the navy
   field their on-navy inline colors (--cc-gold-bright links, white text)
   assume — without it they render on white and fail contrast. */
.block-html .cp-hero {
  background: var(--cc-navy);
  color: var(--color-text-invert);
  padding: var(--space-6) var(--space-5);
  border-radius: var(--radius);
}
/* Headings inside the navy hero must invert too — the site-wide navy heading
   color would otherwise sit navy-on-navy. Inline legacy colors still win. */
.block-html .cp-hero :is(h1, h2, h3, h4, p, li) { color: inherit; }
/* Legacy navy promo band (sheriff inmate-search panel): its inline-styled
   white text and white-bordered outline button assume the navy field the old
   stylesheet painted — without it they render white-on-white (WCAG 1.4.3). */
.block-html .inmate-promo {
  background: var(--cc-navy);
  color: var(--color-text-invert);
  padding: var(--space-6) var(--space-5);
  border-radius: var(--radius);
  display: grid;
  gap: var(--space-4);
}
.block-html .inmate-promo :is(h2, h3, h4, p) { color: inherit; }
/* Links on the navy band: the global navy link color would sit navy-on-navy.
   The legacy gold CTA gets the validated CCWP gold-button pairing. */
.block-html .inmate-promo a { color: inherit; }
.block-html .inmate-promo .btn-gold {
  background: var(--grad-gold-btn);
  color: var(--cc-navy-dark); /* 4.7:1+ ✓ (same pairing as .btn--gold) */
}
/* Legacy inline-styled grids (style="display:grid;grid-template-columns:
   repeat(3,1fr)…") cannot fit a phone viewport and force horizontal scroll
   (WCAG 1.4.10). Until the SPEC §13.4 cleanup pass rewrites them as real
   blocks, collapse them to one column at phone widths only — desktop
   rendering is untouched. !important is required to beat the inline style. */
@media (max-width: 480px) {
  .block-html [style*="grid-template-columns"] { grid-template-columns: minmax(0, 1fr) !important; }
}
/* a trailing full-bleed band sits flush against the footer */
.page-content:has(> .block--full:last-child) { padding-bottom: 0; }

.prose { max-width: var(--content-width); overflow-wrap: anywhere; /* nbsp-glued legacy runs must not force 320px overflow */ }
/* Long-token safety net (WCAG 1.4.10 reflow-320) for the OTHER containers
   that render author/migrated text outside .prose: page-banner H1s and
   breadcrumb trails repeat migrated news titles ("Tax Assessor/Collector's…"
   is one unbreakable token wider than a 320px viewport), the news-article
   summary <p><strong> carries bare URLs, and jobs/meetings detail sections
   render author text directly. `anywhere` only breaks a token that would
   otherwise overflow its line — normal text is untouched. Container-level
   per SPEC §8: never page-level overflow-x clipping. */
.page-banner__title,
.breadcrumbs li,
.page-plain-head h1,
.news-article,
.meeting-next__body,
.page-content section {
  overflow-wrap: anywhere;
}
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose ul, .prose ol { padding-left: 1.4em; margin: 0 0 var(--space-4); }
.prose li { margin-bottom: var(--space-1); }
.prose blockquote {
  margin: var(--space-5) 0;
  padding: var(--space-3) var(--space-5);
  border-left: 4px solid var(--cc-gold);
  background: var(--color-surface-tint);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-family: var(--font-display);
  font-style: italic;
  color: var(--cc-gray-700);
}
.prose--invert, .prose--invert a { color: var(--color-text-invert); }

/* ── 11. Hero (homepage / landing — NO carousel) ────────────────────────── */

.hero {
  position: relative;
  overflow: hidden;             /* clips the Ken Burns zoom, not the page */
  color: var(--color-text-invert);
  min-height: clamp(430px, 58vh, 620px);
  display: flex;
  align-items: center;
}
.hero--compact { min-height: clamp(300px, 38vh, 420px); }
.hero__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 35%;
  animation: hero-kenburns 32s var(--ease-out) alternate infinite;
}
@keyframes hero-kenburns {
  from { transform: scale(1); }
  to   { transform: scale(1.07); }
}
.hero__scrim { position: absolute; inset: 0; background: var(--scrim-hero-grad); }
.hero__seal {
  position: absolute;
  right: -4rem; bottom: -5rem;
  width: 24rem; height: 24rem;
  background: var(--img-seal) center / contain no-repeat;
  opacity: 0.18;
  pointer-events: none;
}
.hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding: var(--space-10) var(--container-pad);
}
.hero__title {
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-6);
  line-height: var(--lh-display);
  color: var(--color-text-invert);
  margin: 0 0 var(--space-3);
  max-width: 18em;
  text-wrap: balance;
  text-shadow: 0 2px 12px var(--shadow-color-deep);
}
.hero__lede {
  font-size: var(--fs-2);
  color: var(--cc-gold-light);             /* on navy scrim ≥ 9.4:1 ✓ */
  font-family: var(--font-display);
  font-style: italic;
  margin: 0 0 var(--space-6);
  max-width: 34em;
}
.hero__search {
  display: flex;
  gap: var(--space-2);
  max-width: 40rem;
  margin-bottom: var(--space-5);
}
.hero__search input {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-1);
  padding: var(--space-4) var(--space-5);
  border: 2px solid var(--white-alpha-35);
  border-radius: var(--radius);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-3);
}
.hero__chips {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.hero-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--white-alpha-18);
  border: 1px solid var(--white-alpha-35);
  color: var(--color-text-invert);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-4);
  min-height: 44px;
  font-weight: var(--fw-semibold);
  backdrop-filter: blur(4px);
  transition: background var(--transition), transform var(--transition);
}
.hero-chip:hover { background: var(--cc-gold-bright); color: var(--cc-navy-dark); transform: translateY(-1px); }
.hero-chip .icon { color: var(--cc-gold-bright); }
.hero-chip:hover .icon { color: var(--cc-navy-dark); }

/* ── 11a. Hero SLIDESHOW (blocks/hero-slider.js) ──────────────── [MODULE T2]
   APPEND-ONLY. Nothing in §11 above was edited, so `hero-banner` renders
   byte-identically to how it always has; every rule below is scoped to
   `.hero--slider` or to a class only the slider emits.

   SPEC §3.3 said "Homepage: NO carousel". It was AMENDED on Chris's
   instruction (see SPEC.md §3.3) to allow ONE user-controlled slideshow whose
   search box and task chips never rotate. This is that amendment.

   THE SCRIM IS THE WHOLE POINT OF THIS SECTION. The old site's slider put a
   105° gradient that decayed to .08 alpha over a sunlit limestone courthouse
   and got 2.89:1 body text — a WCAG 1.4.3 failure that `text-shadow` hid from
   sighted review. Here the scrim is ONE element OUTSIDE the rotating layer,
   built from three token layers with a hard alpha floor, so no per-slide art
   direction can weaken it:

       layer 1 (top)     115° --scrim-navy .82 → transparent   (the look)
       layer 2           --scrim-hero-grad  .92 / .78 / .55    (the platform)
       layer 3 (bottom)  --scrim-navy-soft  .55 flat           (the FLOOR)

   Effective alpha is 1-(1-a1)(1-a2)(1-a3): 0.993 at the headline end and
   never below 0.798 anywhere, on any photo, at any viewport.

   MEASURED, not eyeballed (scratchpad/hero-probe.mjs composites the real
   JPEGs under these exact stops in sRGB and applies the WCAG formula —
   4 viewports × 3 photos × both ends of the Ken Burns zoom, sampling the
   WHOLE hero box, not a chosen text column):

       white text  (.hero__title, .hero__badge, chips)  worst  6.39:1
       gold lede   (.hero__lede, --cc-gold-light)       worst  5.17:1
       chip label  (fill --scrim-navy-soft)             worst 10.58:1
       badge white on --cc-red                                 6.47:1  (opaque)
       .btn--gold  navy-dark on the gold ramp             5.71–7.39:1  (opaque)
       .btn--white navy-dark on solid white                    15.43:1 (opaque)

   For comparison the same probe scores the UNMODIFIED --scrim-hero-grad at
   2.49:1 worst over the whole box — it is safe only in the text column it was
   tuned for, which is exactly the fragility this section removes. */

/* Everything else — height, overflow clipping, the flex centring of
   .hero__inner, the seal — is inherited from §11 unchanged. */
.hero--slider { --dur-hero-fade: 0.9s; }   /* the old site's cross-fade was 1.1s */

/* ── backdrops: full-bleed, behind BOTH the rotating and the fixed layer ── */
.hero__backdrops { position: absolute; inset: 0; }
.hero--slider .hero__bg {
  opacity: 0;
  animation: none;                      /* only the visible photo animates */
  transition: opacity var(--dur-hero-fade) var(--ease-out);
}
.hero--slider .hero__bg.is-active {
  opacity: 1;
  animation: hero-kenburns 32s var(--ease-out) alternate infinite;
}
/* A slide with no photograph — the accessible equivalent of the old slide 3's
   flat gradient, in county navy rather than its off-brand greens. */
.hero__bg--tone {
  background-image: linear-gradient(135deg,
    var(--cc-navy) 0%, var(--cc-navy-mid) 45%, var(--cc-navy-dark) 100%);
}

.hero--slider .hero__scrim {
  background:
    linear-gradient(115deg, var(--scrim-navy) 0%, var(--scrim-navy) 45%, transparent 100%),
    var(--scrim-hero-grad),
    var(--scrim-navy-soft);
}

/* ── the rotating text layer ──────────────────────────────────────────────
   All slides occupy ONE grid cell, so the row reserves the tallest slide's
   height and nothing below the hero moves when the headline changes.
   `visibility` — not `opacity` — is what takes an inactive slide out of the
   accessibility tree AND the tab order; `inert` (server-rendered, maintained
   by public.js) is the belt to that braces. */
.hero--slider .hero__slides { display: grid; }
.hero--slider .hero__slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-hero-fade) var(--ease-out),
              visibility 0s linear var(--dur-hero-fade);
}
.hero--slider .hero__slide.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-hero-fade) var(--ease-out), visibility 0s;
}
.hero--slider .hero__slide > :last-child { margin-bottom: 0; }

.hero__badge {
  display: inline-block;
  margin: 0 0 var(--space-3);
  padding: var(--space-1) var(--space-4);
  background: var(--cc-red);                 /* white on it 6.47:1 ✓ */
  color: var(--color-text-invert);
  font-family: var(--font-ui);
  font-size: var(--fs-meta);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: var(--radius-full);
}
.hero--slider .hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0;
}
/* The old slider's secondary button was rgba(255,255,255,.15) on the photo —
   2.87:1, a straight 1.4.3 failure. Solid, inside the slider only. */
.hero--slider .btn--white {
  background: var(--color-surface);
  border-color: var(--white-alpha-70);
  color: var(--cc-navy-dark);                /* on white 15.43:1 ✓ */
  backdrop-filter: none;
}
.hero--slider .btn--white:hover {
  background: var(--cc-gold-light);
  color: var(--cc-navy-dark);                /* on gold-light 13.1:1 ✓ */
}

/* ── the PERSISTENT layer — search + chips, rendered once, never rotates ── */
.hero--slider .hero__fixed {
  position: relative;
  z-index: 2;
  margin-top: var(--space-6);
}
.hero--slider .hero__search { margin-bottom: var(--space-4); }
/* Navy-tinted rather than white-tinted: the chips now sit over WHATEVER photo
   is showing, and a white wash lifts the background under white text. Measured
   10.58:1 worst against 4.54:1 for the inherited --white-alpha-18 fill. */
.hero--slider .hero-chip { background: var(--scrim-navy-soft); }

/* ── controls: present at EVERY breakpoint, 44px targets, opaque chips ──── */
.hero__controls {
  position: relative;
  z-index: 3;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-5);
}
/* The server renders the row `hidden` and public.js un-hides it. A class
   selector beats the UA's `[hidden] { display: none }`, so without this line
   a visitor with JavaScript off gets a full set of buttons that do nothing —
   caught in a real no-JS browser run, not by reading the code. */
.hero__controls[hidden] { display: none; }
.hero__ctrl {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  min-width: 44px; min-height: 44px;
  padding: 0;
  border: 2px solid var(--white-alpha-70);   /* boundary vs the scrim ≥ 3:1 ✓ */
  border-radius: var(--radius-full);
  background: var(--scrim-navy);
  color: var(--color-text-invert);
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition);
}
.hero__ctrl:hover {
  background: var(--cc-gold-bright);
  border-color: var(--cc-gold-bright);
  color: var(--cc-navy-dark);
}
.hero__ctrl .icon { width: 20px; height: 20px; }

/* Play / pause glyph. There is no `pause` symbol in the sprite, so both states
   are drawn in CSS — decorative; the button's accessible NAME carries state
   (`Play slideshow` ↔ `Pause slideshow`), never colour or shape alone. */
.hero__glyph { position: relative; display: block; width: 16px; height: 16px; }
.hero__glyph::before {
  content: '';
  position: absolute; top: 0; left: 3px;
  width: 0; height: 0;
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  border-left: 13px solid currentColor;      /* ▶ paused */
}
.hero__ctrl--toggle[data-playing="true"] .hero__glyph::before,
.hero__ctrl--toggle[data-playing="true"] .hero__glyph::after {
  content: '';
  position: absolute; top: 1px;
  width: 4px; height: 14px;
  border: 0;
  border-radius: 1px;
  background: currentColor;                  /* ▮▮ playing */
}
.hero__ctrl--toggle[data-playing="true"] .hero__glyph::before { left: 2px; }
.hero__ctrl--toggle[data-playing="true"] .hero__glyph::after { right: 2px; }

.hero__dots {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin: 0; padding: 0;
}
/* 44px target with a 12px visual dot — the old slider used 24px, the bare
   WCAG 2.5.8 floor, while every other control on this site is 44px. */
.hero__dot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  min-width: 44px; min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.hero__dot::before {
  content: '';
  display: block;
  width: 12px; height: 12px;
  border: 2px solid var(--white-alpha-70);
  border-radius: 50%;
  background: transparent;
  transition: background var(--transition), transform var(--transition);
}
.hero__dot[aria-current="true"]::before {
  background: var(--cc-gold-bright);
  border-color: var(--cc-gold-bright);
  transform: scale(1.2);
}
.hero__dot:hover::before { background: var(--white-alpha-70); }

/* Staggered entrance, matching the old site's badge → headline → text →
   buttons cascade. */
@keyframes hero-slide-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.hero--slider .hero__slide.is-active > * {
  animation: hero-slide-in 0.6s var(--ease-out) both;
}
.hero--slider .hero__slide.is-active > :nth-child(2) { animation-delay: 0.08s; }
.hero--slider .hero__slide.is-active > :nth-child(3) { animation-delay: 0.16s; }
.hero--slider .hero__slide.is-active > :nth-child(4) { animation-delay: 0.24s; }

/* §32's blanket rule collapses DURATION but not DELAY, and an animation with
   `both` fill sits at its `from` state (opacity 0) during the delay — which
   would flash the headline out. Kill the animations outright instead. The
   auto-advance itself is stopped in JS, not here (public.js REDUCED_MOTION):
   a hard cut every 8s is worse than the fade it replaces. */
@media (prefers-reduced-motion: reduce) {
  .hero--slider .hero__slide,
  .hero--slider .hero__bg { transition: none; }
  .hero--slider .hero__bg.is-active { animation: none; }
  .hero--slider .hero__slide.is-active > * { animation: none; }
}

/* In print the photo and the scrim go away, so the white text has to come
   back to ink. Only the slide the reader was looking at prints — the others
   stay `visibility:hidden`, which is what they are on screen too. */
@media print {
  .hero__controls,
  .hero--slider .hero__backdrops,
  .hero--slider .hero__scrim,
  .hero--slider .hero__seal { display: none !important; }
  .hero--slider,
  .hero--slider .hero__title,
  .hero--slider .hero__lede { color: CanvasText; }
  .hero__badge {
    background: none;
    color: CanvasText;
    border: 1px solid CanvasText;
  }
}

.page-content > .block-hero-slider:first-child { margin-top: calc(-1 * var(--space-6)); }

/* ── 12. Buttons ────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  padding: var(--space-3) var(--space-5);
  min-height: 44px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition),
              background var(--transition), color var(--transition);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.btn:active { transform: translateY(0); }

/* `.btn--navy` is the same button. The Document Center and the foreclosure
   page were written against that name and shipped with no rule for it, so
   every "Search" control on both rendered as the browser's default grey box
   (V-01/V-04). It is an ALIAS, not a second variant: one declaration, so the
   navy button can never drift into two slightly different navies. */
.btn--primary, .btn--navy { background: var(--grad-navy-btn); color: var(--color-text-invert); }
.btn--primary:hover, .btn--navy:hover { color: var(--color-text-invert); }
.btn--gold { background: var(--grad-gold-btn); color: var(--cc-navy-dark); } /* 4.7:1+ ✓ */
.btn--gold:hover { color: var(--cc-navy-dark); }
.btn--outline {
  background: transparent;
  border-color: var(--cc-navy);
  color: var(--cc-navy);
}
.btn--outline:hover { background: var(--cc-navy); color: var(--color-text-invert); }
.btn--white {
  background: var(--white-alpha-18);
  border-color: var(--white-alpha-35);
  color: var(--color-text-invert);
  backdrop-filter: blur(4px);
}
.btn--white:hover { background: var(--color-surface); color: var(--cc-navy); }
.btn--sm { padding: var(--space-2) var(--space-4); min-height: 36px; }
.btn--lg { padding: var(--space-4) var(--space-7); font-size: var(--fs-1); }

.block-button--center { text-align: center; }

/* ── 13. Cards & tiles ──────────────────────────────────────────────────── */

.card-grid, .people-grid {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--space-4);
  /* minmax(0, 1fr): a bare 1fr track's min-size is auto, so a card whose
     content has a wide min-content (long words, badges) blows the track past
     the viewport at 320 px. Clamp the min to 0 and let text wrap. */
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 480px) {
  .card-grid, .people-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  /* `cols: 2` was the one column count with no rule of its own. It rendered
     two-up only because the 480px base happens to be two, so the block's
     declared column count and the column count on screen agreed by accident —
     and would have silently disagreed the moment the base changed. State it. */
  .card-grid--2, .people-grid.card-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .card-grid--3, .people-grid.card-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .card-grid--4, .people-grid.card-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.card {
  position: relative;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
  box-shadow: var(--shadow-1);
  transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
/* Flex-row (icon chip beside body) belongs ONLY to the cards-block variant.
   Plain .card is a stacked box: feature routes (jobs, foreclosures, plats)
   and imported legacy html blocks use .card as a generic container with many
   children — a flex-row default laid those children out horizontally and
   forced page-level horizontal scroll at 320 px (WCAG 1.4.10). */
.card--cards {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}
.card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-3);
  border-color: var(--cc-gold);
}
.card--tiles {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  background: var(--color-surface);
}
.card-title { font-size: var(--fs-2); font-weight: var(--fw-bold); margin: 0 0 var(--space-1); font-family: var(--font-ui); }
.card-title a { color: var(--cc-navy); }
/* whole-card click without a giant link name */
.card-link::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius); }
.card-desc { margin: 0; color: var(--color-text-muted); }

/* Duotone icon chips (navy stroke on gold-tinted disc) */
.icon-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px; height: 56px;
  flex: none;
  border-radius: var(--radius-full);
  background: radial-gradient(circle at 30% 30%, var(--cc-gold-light), var(--gold-alpha-25));
  border: 1px solid var(--gold-alpha-25);
  color: var(--cc-navy);
}
.icon-chip .icon { width: 26px; height: 26px; }
.card:hover .icon-chip { background: var(--cc-navy); color: var(--cc-gold-bright); }

/* People cards */
.person-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
  text-align: center;
  transition: transform var(--transition), box-shadow var(--transition);
}
.person-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
.person-card__photo { margin-bottom: var(--space-3); }
.person-card__img, .person-card__placeholder {
  width: 112px; height: 112px;
  border-radius: var(--radius-full);
  object-fit: cover;
  display: inline-block;
  border: 3px solid var(--cc-gold-light);
}
.person-card__placeholder {
  background: var(--cc-navy-light) var(--img-seal) center / 60% no-repeat;
  opacity: 0.7;
}
.person-card__name { font-family: var(--font-ui); font-weight: var(--fw-bold); font-size: var(--fs-2); margin: 0; color: var(--cc-navy); }
.person-card__role { color: var(--cc-gold-text); font-weight: var(--fw-semibold); margin: var(--space-1) 0 var(--space-2); }
.person-card__contact { margin: 0; }

/* Fact cards (county facts band — reuses card striping) */
.fact-card {
  background: var(--color-surface-brand);
  border-radius: var(--radius);
  padding: var(--space-5);
  text-align: center;
}
.fact-card__number {
  display: block;
  font-family: var(--font-ui);
  font-weight: var(--fw-heavy);
  font-size: var(--fs-4);
  color: var(--cc-navy);
}
.fact-card__label { color: var(--color-text-muted); }

/* ── 14. Figures / image blocks ─────────────────────────────────────────── */

.figure { margin: 0; }
.figure img { border-radius: var(--radius); box-shadow: var(--shadow-2); }
.figure--small { max-width: 24rem; }
.figure--content { max-width: var(--content-width); }
.figure figcaption {
  margin-top: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--fs-0);
}
.figure-credit { font-size: var(--fs-meta); text-transform: uppercase; letter-spacing: 0.05em; }

.image-text {
  display: grid;
  gap: var(--space-6);
  align-items: center;
}
@media (min-width: 768px) {
  .image-text { grid-template-columns: 1fr 1fr; }
  .image-text--left .image-text__media { order: -1; }
  .image-text--right .image-text__media { order: 1; }
}
.image-text__img { border-radius: var(--radius); box-shadow: var(--shadow-2); width: 100%; object-fit: cover; }

/* ── 15. Callouts & navy band ───────────────────────────────────────────── */

.callout {
  display: flex;
  gap: var(--space-3);
  border-radius: var(--radius);
  padding: var(--space-5);
  border-left: 4px solid;
  max-width: var(--content-width);
}
/* `flex: none` on the SPAN, not just on the svg inside it.
   The span is the flex item. The global `img, svg, video { max-width: 100% }`
   at §1 drops the svg's min-content contribution to zero, so the span was free
   to shrink — and then max-width:100% capped the icon at the span's collapsed
   width. Every callout on the site rendered its 1.5em icon at about 3px. Same
   reason `.banner-contact__item svg` carries `flex: none`. */
.callout__icon { flex: none; }
.callout__icon .icon { width: 1.5em; height: 1.5em; }
.callout__title { font-weight: var(--fw-bold); margin: 0 0 var(--space-1); font-size: var(--fs-1); }
.callout__body > .prose { max-width: none; }
.callout__cta { margin: var(--space-3) 0 0; }
.callout--info    { background: var(--alert-info-bg);    border-color: var(--cc-navy-mid); color: var(--cc-navy-dark); }
.callout--info .callout__icon { color: var(--cc-navy-mid); }
.callout--warning { background: var(--alert-warning-bg); border-color: var(--cc-gold); color: var(--cc-gray-900); }
.callout--warning .callout__icon, .callout--warning .callout__title { color: var(--alert-warning-accent); }
.callout--urgent  { background: var(--cc-red-light); border-color: var(--cc-red); color: var(--cc-gray-900); }
.callout--urgent .callout__icon, .callout--urgent .callout__title { color: var(--cc-red); }
.callout--success { background: var(--alert-success-bg); border-color: var(--cc-green); color: var(--cc-gray-900); }
.callout--success .callout__icon, .callout--success .callout__title { color: var(--cc-green); }

/* A compact county notice: one or two lines with a gold edge, for a page that
   needs the notice PRESENT without spending 398px of a phone screen on it.
   Shipped first as `.fc-note` on /foreclosures; kept as an alias so that page
   renders byte-identically and needs no markup change. New markup should use
   `.note-strip`.
   `--warning` is the only modifier and exists for one reason: on /unclaimed
   this strip stands in for a `.callout--warning` and links to it, so it has to
   read as the same family rather than as a neutral aside. --cc-gray-900 on
   --cc-gold-light measures 13.1:1; a link inside it is --color-link
   (--cc-navy-mid) at 6.5:1 on that fill and stays underlined by section 1's
   `main p a`, so colour is never the only cue. */
.note-strip, .fc-note {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-tint);
  border-left: 4px solid var(--cc-gold);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.note-strip--warning { background: var(--cc-gold-light); }

.band-navy {
  background:
    radial-gradient(60rem 60rem at 110% 120%, var(--navy-alpha-15), transparent),
    var(--color-surface-dark);
  color: var(--color-text-invert);
  padding-block: var(--section-pad);
  position: relative;
  overflow: hidden;
}
.band-navy::before {           /* faint seal watermark */
  content: "";
  position: absolute;
  left: -6rem; top: -6rem;
  width: 22rem; height: 22rem;
  background: var(--img-seal) center / contain no-repeat;
  opacity: 0.1;
  pointer-events: none;
}
.band-navy__inner {
  position: relative;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--container-pad);
  text-align: center;
}
.band-navy__title {
  color: var(--color-text-invert);
  font-size: var(--fs-4);
  margin-bottom: var(--space-3);
}
.band-navy__body { max-width: 44rem; margin-inline: auto; }
.band-navy .callout__cta, .band-navy__inner .callout__cta { margin-top: var(--space-5); }

/* ── 16. Accordion ──────────────────────────────────────────────────────── */

.accordion { max-width: var(--content-width); }
.accordion__item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  margin-bottom: var(--space-3);
  box-shadow: var(--shadow-1);
}
.accordion__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  cursor: pointer;
  list-style: none;
  padding: var(--space-4) var(--space-5);
  font-weight: var(--fw-semibold);
  color: var(--cc-navy);
  min-height: 48px;
  border-radius: var(--radius);
}
.accordion__summary::-webkit-details-marker { display: none; }
.accordion__summary:hover { background: var(--color-surface-tint); }
.accordion__chevron { color: var(--cc-gold-text); transition: transform var(--transition); }
.accordion__item[open] > .accordion__summary { border-bottom: 1px solid var(--color-border); border-radius: var(--radius) var(--radius) 0 0; }
.accordion__item[open] > .accordion__summary .accordion__chevron { transform: rotate(180deg); }
.accordion__panel { padding: var(--space-4) var(--space-5); }

/* ── 17. Tables ─────────────────────────────────────────────────────────── */

.table-scroll {
  overflow-x: auto;
  /* contain:content — Chromium leaks a wide table's overflow through the
     scroll container into the viewport's scrollable region (page scrolls
     sideways to blank space at 320 px). Paint containment stops the leak;
     the internal scrolling is unaffected. */
  contain: content;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  background: var(--color-surface);
}
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-0);
}
.data-table caption {
  text-align: left;
  padding: var(--space-4) var(--space-5) var(--space-2);
  font-weight: var(--fw-bold);
  color: var(--cc-navy);
  font-family: var(--font-display);
  font-size: var(--fs-2);
}
.data-table th, .data-table td {
  text-align: left;
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  vertical-align: top;
}
.data-table thead th {
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* 11.6:1 ✓ */
  font-weight: var(--fw-semibold);
  border-top: 0;
  white-space: nowrap;
}
.data-table tbody th { background: var(--color-surface-tint); font-weight: var(--fw-semibold); }
.data-table tbody tr:nth-child(even) td { background: var(--color-surface-tint); }
.data-table tbody tr:hover td, .data-table tbody tr:hover th { background: var(--cc-navy-light); }

/* ── 18. Document lists ─────────────────────────────────────────────────── */

.doc-list {
  list-style: none;
  margin: 0; padding: 0;
  max-width: var(--content-width);
}
.doc-item + .doc-item { margin-top: var(--space-2); }
.doc-link {
  display: flex;
  flex-wrap: wrap;              /* long titles + nowrap meta wrap at 320 px */
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: var(--radius);
  background: var(--color-surface);
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}
.doc-link:hover {
  border-left-color: var(--cc-gold);
  transform: translateX(2px);
  box-shadow: var(--shadow-1);
}
.doc-link__icon { color: var(--cc-navy-mid); align-self: center; }
/* Archive file names are the county's own and often have no spaces at all
   ("CaldwellCountyMUD7ElectionOrder05042024", "NoticeofDeliveryofBallotsVotedByMail").
   A single 39-character token is ~360 px and forces the whole page to scroll
   at 320 px (WCAG 1.4.10 Reflow). Same treatment, same reason, as .prose and
   .block-html above. `min-width: 0` lets it shrink inside the flex row. */
.doc-link__label {
  font-weight: var(--fw-semibold);
  color: var(--color-link);
  min-width: 0;
  overflow-wrap: anywhere;
}
.doc-link__meta { color: var(--color-text-muted); white-space: nowrap; font-size: var(--fs-meta); }

/* .doc-link__meta is deliberately nowrap — it is a two-word annotation glued
   to the end of a link ("(PDF, 2.1 MB)") and must never break across lines.
   That makes it the WRONG class for a standalone muted SENTENCE, which is what
   the meeting and election archives print under each record ("Filed in 2019 —
   the county filing does not state the election date"). Set nowrap, such a
   sentence is ~450 px of untouchable text and pushes the page body into
   horizontal scroll at 320 px (WCAG 1.4.10 Reflow — measured). This is the
   same annotation voice, allowed to wrap. */
.archive-meta {
  color: var(--color-text-muted);
  font-size: var(--fs-meta);
  margin: 0 0 var(--space-3);
  overflow-wrap: anywhere;
}

/* A section heading is not always prose. Archive sections name the folder they
   publish ("Unclassified archive documents — filed under
   public-documents/misc/unscoped") and group headings are folder display names
   straight out of the File Manager, so a heading can be a single unbreakable
   30+ character token — 351 px at heading size, which forces the WHOLE PAGE to
   scroll at 320 px (WCAG 1.4.10 Reflow). Same treatment, same reason, as
   .doc-link__label above and .prose / .block-html earlier. Scoped to
   block-rendered headings rather than the global h1–h6 rule so hero and card
   headings keep their existing intrinsic sizing. */
.block-heading__h,
.doc-list__title,
.doc-group__title { overflow-wrap: anywhere; }

/* Folder-linked lists group by subfolder (e.g. sample ballots by election). */
.doc-group + .doc-group { margin-top: var(--space-5); }
.doc-list__title + .doc-group { margin-top: var(--space-4); }
.doc-group__title {
  font-size: var(--fs-2);
  margin: 0 0 var(--space-3);
  color: var(--color-text);
}
.doc-list__more { margin: var(--space-4) 0 0; }
.doc-more-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--fw-semibold);
}
.doc-more-link__icon { flex: none; }

/* ── 19. Quick links / task chips ───────────────────────────────────────── */

.quicklinks { list-style: none; margin: 0; padding: 0; }
.quicklinks--chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.task-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--color-surface-brand);
  color: var(--cc-navy);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-4);
  min-height: 44px;
  font-weight: var(--fw-semibold);
  transition: background var(--transition), color var(--transition), transform var(--transition);
}
.task-chip:hover { background: var(--cc-navy); color: var(--cc-gold-light); transform: translateY(-1px); }
.task-chip .icon { color: var(--cc-gold-text); }
.task-chip:hover .icon { color: var(--cc-gold-bright); }

.quicklinks--list { max-width: var(--content-width); }
.quicklinks--list li + li { margin-top: var(--space-2); }
.quicklink-row {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.quicklink-row:hover { border-color: var(--cc-gold); box-shadow: var(--shadow-1); }
.quicklink-row__icon { color: var(--cc-gold-text); margin-top: 0.15em; }
/* The label/description column beside the icon. A flex item's min-width is
   `auto`, so without this the column refuses to shrink below its longest
   unbroken token and a quick link whose label is a URL or a long file name
   pushes the row past its card. 136 of these on 11 pages. */
.quicklink-row__text { min-width: 0; flex: 1 1 auto; }
.quicklink-row__label { font-weight: var(--fw-semibold); color: var(--color-link); display: block; }
.quicklink-row__desc { display: block; color: var(--color-text-muted); }

/* ── 20. Contact card ───────────────────────────────────────────────────── */

.contact-card {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-top: 4px solid var(--cc-gold);
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
  padding: var(--space-6);
  max-width: var(--content-width);
}
.contact-photo {
  width: 128px; height: 128px;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 3px solid var(--cc-gold-light);
}
.contact-card__main { flex: 1; min-width: 16rem; }
.contact-card__dept { margin: 0; color: var(--cc-gold-text); font-weight: var(--fw-semibold); font-size: var(--fs-meta); text-transform: uppercase; letter-spacing: 0.06em; }
.contact-card__name { margin: var(--space-1) 0 0; font-family: var(--font-ui); font-weight: var(--fw-bold); font-size: var(--fs-3); color: var(--cc-navy); }
.contact-card__role { margin: 0 0 var(--space-3); color: var(--color-text-muted); }
.contact-card__rows { display: grid; gap: var(--space-3); margin-top: var(--space-3); }
.contact-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-start; min-width: 0; }
.contact-row .icon { color: var(--cc-navy-mid); margin-top: 0.2em; }
/* Long unbroken values (emails, URLs) shrink + wrap instead of widening the card */
.contact-row__text { min-width: 0; overflow-wrap: anywhere; }
.contact-row__label {
  display: block;
  font-size: var(--fs-meta);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  font-weight: var(--fw-semibold);
}
/* The label of a RECORD row, as distinct from the caption of a contact card.
   `.contact-row__label` above is 15px ALL-CAPS letter-spaced, which is right
   for a staff card and wrong for the county's statement of what it owes
   somebody: it wrapped "NAME ON THE RECORD" to two lines beside a one-line
   value, and the claim wizard's review rendered a six-line shouted question
   above a four-digit answer. Uppercase removes word-shape recognition, which is
   what an older reader leans on hardest. Sentence case, one size up, same ink.
   Consumers today: the unclaimed record page, the claim status page and the
   wizard review. Any future page that renders a record should use this. */
.def-label {
  display: block;
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  color: var(--cc-gray-700);     /* 10.0:1 on white — well above the AA floor */
}
.contact-map-link { white-space: nowrap; }

/* ── 21. Embeds ─────────────────────────────────────────────────────────── */

.embed { margin: 0; max-width: var(--content-width); }
.embed__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-3);
  background: var(--cc-navy-dark);
}
.embed__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  border: 0;
}
.embed figcaption { margin-top: var(--space-2); color: var(--color-text-muted); }

/* ── 22. Dividers ───────────────────────────────────────────────────────── */

.divider--line { max-width: var(--content-width); margin-inline: 0; }
.divider--space { height: var(--space-8); }
.divider--flourish {
  height: var(--space-6);
  background: var(--img-seal) center / auto 100% no-repeat;
  opacity: 0.25;
}

/* ── 23. Section head + news / events / meeting (auto blocks) ───────────── */

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.section-head > :first-child { margin-bottom: 0; }
.section-head__more {
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}
.section-head__more::after { content: " →"; }

.news-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .news-grid { grid-template-columns: repeat(2, 1fr); }
  .news-grid--featured .news-card--featured { grid-column: 1 / -1; }
}
@media (min-width: 1024px) {
  .news-grid { grid-template-columns: repeat(3, 1fr); }
  .news-grid--featured { grid-template-columns: 2fr 1fr 1fr; }
  .news-grid--featured .news-card--featured { grid-column: auto; grid-row: span 2; }
}
.news-card {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-1);
  transition: transform var(--transition), box-shadow var(--transition);
}
.news-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.news-card__media { aspect-ratio: 16 / 9; background: var(--cc-navy-light); }
.news-card__img { width: 100%; height: 100%; object-fit: cover; }
.news-card__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.news-card__title { font-family: var(--font-ui); font-weight: var(--fw-bold); font-size: var(--fs-2); margin: 0; }
.news-card__title a { color: var(--cc-navy); }
.news-card__title a:hover { color: var(--cc-gold-text); }
.news-card__summary { margin: 0; color: var(--color-text-muted); }
.news-card__date { color: var(--color-text-muted); font-size: var(--fs-meta); margin-top: auto; }
.news-card--featured .news-card__title { font-size: var(--fs-3); font-family: var(--font-display); font-weight: var(--fw-black); }

.event-list { list-style: none; margin: 0; padding: 0; max-width: var(--content-width); }
.event-row {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  margin-bottom: var(--space-3);
  box-shadow: var(--shadow-1);
}
.event-row__date {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 64px; height: 64px;
  background: var(--cc-navy);
  color: var(--color-text-invert);
  border-radius: var(--radius);
  line-height: 1.1;
}
.event-row__month { font-size: var(--fs-meta); text-transform: uppercase; letter-spacing: 0.06em; color: var(--cc-gold-bright); font-weight: var(--fw-bold); }
.event-row__day { font-size: var(--fs-3); font-weight: var(--fw-heavy); font-family: var(--font-ui); }
.event-row__title { font-family: var(--font-ui); font-size: var(--fs-1); font-weight: var(--fw-bold); margin: 0 0 var(--space-1); }
.event-row__meta { margin: 0; color: var(--color-text-muted); }

/* Next-meeting hero card (SPEC §5) */
.meeting-next {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-top: 4px solid var(--cc-gold);
  border-radius: var(--radius);
  box-shadow: var(--shadow-3);
  padding: var(--space-6);
  max-width: var(--content-width);
}
.meeting-next--cancelled { border-top-color: var(--cc-red); }
.meeting-next__body p { display: flex; align-items: baseline; gap: var(--space-3); margin: 0 0 var(--space-3); }
.meeting-next__body .icon { color: var(--cc-navy-mid); align-self: center; }
.meeting-next__when { font-size: var(--fs-2); font-weight: var(--fw-bold); color: var(--cc-navy); }
.meeting-next__countdown { color: var(--cc-gold-text); font-weight: var(--fw-semibold); }
.meeting-next__posted { color: var(--cc-green); font-weight: var(--fw-semibold); }
.meeting-next__posted .icon { color: var(--cc-green); }
.meeting-next__posted--pending { color: var(--color-text-muted); }
.meeting-next__posted--pending .icon { color: var(--color-text-muted); }
.meeting-next__status--cancelled { color: var(--cc-red); font-weight: var(--fw-bold); }
.meeting-next__status--cancelled .icon { color: var(--cc-red); }
.meeting-next__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-5);
}
.meeting-next__archive { margin: var(--space-4) 0 0; }

/* Empty state (MODULE F3 / FULL-REVIEW P0-8). When no dated meeting record
   exists the card falls back to the standing schedule the county publishes,
   so the site's most prominent civic slot never renders a bare dead end. The
   standing sentence IS the answer to "when does the Court next meet", so it
   carries the same weight and ink as a real date — muted secondary text here
   would bury the one fact the reader came for. */
.meeting-next--empty .meeting-next__standing {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  font-size: var(--fs-1);
  font-weight: var(--fw-semibold);
  color: var(--cc-navy);
}
.meeting-next--empty .meeting-next__standing .icon {
  color: var(--cc-navy-mid);
  align-self: center;
  flex: none;
}
.meeting-next--empty .meeting-next__archive { margin-top: var(--space-4); }

/* ── 24. Forms (labels, errors, focus — SPEC §3.3) ──────────────────────── */

.field { margin-bottom: var(--space-5); max-width: 32rem; }
.field label {
  display: block;
  font-weight: var(--fw-semibold);
  color: var(--cc-navy-dark);
  margin-bottom: var(--space-1);
}
.field__hint { color: var(--color-text-muted); margin: 0 0 var(--space-2); }
input[type="text"], input[type="search"], input[type="email"], input[type="tel"],
input[type="url"], input[type="number"], input[type="date"], input[type="time"],
input[type="password"], select, textarea {
  font-family: var(--font-ui);
  font-size: max(16px, 1em);   /* prevents iOS zoom-on-focus */
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  min-height: 44px;
  width: 100%;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.header-search input, .hero__search input, .mobile-menu__search input,
.toolbar input, .toolbar select { width: auto; }
textarea { min-height: 8rem; resize: vertical; }
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--cc-red);
  box-shadow: 0 0 0 3px var(--cc-red-light);
}
.field-error {
  display: flex;
  align-items: baseline;
  gap: var(--space-1);
  color: var(--cc-red);                    /* 6.5:1 on white ✓ */
  font-weight: var(--fw-semibold);
  margin-top: var(--space-1);
}
/* The claim form renders an EMPTY, hidden .field-error slot for every field, so
   public.js only ever writes textContent and a client error is the same markup
   as a server error. `display: flex` above is (0,1,0) and BEATS the UA sheet's
   `[hidden] { display: none }` (0,0,0), so without this line every field grows
   an empty red row. Confirmed in a browser, not reasoned about — the same
   failure and the same fix as `.hero__controls[hidden]` in §11a.
   Kept here in §24 beside the component it guards, NOT scoped to a page: if
   errorSlot is ever used on /jobs, a page-scoped guard would silently not
   apply. */
.field-error[hidden] { display: none; }
fieldset { border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-5); margin: 0 0 var(--space-5); }
legend { font-weight: var(--fw-bold); color: var(--cc-navy); padding-inline: var(--space-2); }

/* ── 25. Badges ─────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  border-radius: var(--radius-full);
  padding: 0 var(--space-3);
  min-height: 24px;
  border: 1px solid currentColor;          /* non-color cue (1.4.1) */
}
.badge--navy    { color: var(--cc-navy);       background: var(--cc-navy-light); }
.badge--gold    { color: var(--cc-gold-text);  background: var(--cc-gold-light); }
.badge--red     { color: var(--cc-red);        background: var(--cc-red-light); }
.badge--green   { color: var(--cc-green);      background: var(--cc-green-light); }
.badge--neutral { color: var(--cc-gray-600);   background: var(--cc-gray-100); }

/* ── 26. Toolbar / filter rail (plats, news, jobs, meetings archive) ────── */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}
.toolbar__search { display: flex; gap: var(--space-2); flex: 1 1 16rem; min-width: 0; }
.toolbar__search input { flex: 1; min-width: 0; }
/* A <select>'s intrinsic width is its LONGEST OPTION, and a flex item defaults
   to min-width:auto, so a long option list cannot shrink and pushes the PAGE
   BODY into horizontal scroll at 320 px (WCAG 1.4.10 Reflow — measured on the
   meetings archive, whose type filter lists derived meeting titles such as
   "Commissioners Court — Regular Meeting (341)": 543 px in a 320 px viewport).
   The full option text is still shown when the menu is open. */
.toolbar__field { flex: 1 1 12rem; min-width: 0; }
.toolbar__field select { width: 100%; max-width: 100%; }
.toolbar__count {
  margin: 0 0 0 auto;
  color: var(--color-text-muted);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0 0 var(--space-5); padding: 0;
}
.chip {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-link);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-0);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.chip:hover { background: var(--cc-navy-light); }
.chip[aria-pressed="true"], .chip.is-selected, .chip[aria-current] {
  background: var(--cc-navy);
  border-color: var(--cc-navy);
  color: var(--color-text-invert);
}

.filter-layout {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 1024px) {
  .filter-layout { grid-template-columns: 260px minmax(0, 1fr); align-items: start; }
}
.filter-rail {
  background: var(--color-surface-tint);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
}
.filter-rail h2, .filter-rail h3 {
  font-family: var(--font-ui);
  font-size: var(--fs-1);
  font-weight: var(--fw-bold);
  margin-bottom: var(--space-3);
}
.filter-rail .field { margin-bottom: var(--space-4); max-width: none; }

/* ── page layout: one reading column plus a companion rail ─────────────────
   /foreclosures shipped this first as `.fc-layout` and it is the shape every
   long public list page wants: main fills the container, the rail carries the
   advisories, and NOTHING is left flush-left against several hundred pixels of
   dead white. Lives here rather than being copied under a page prefix, which
   would have been the third copy of one grid in this file.
   The rail WIDTH is a per-page decision, not a component default: an advisory
   rail has to be wide enough for the longest paragraph put in it. /foreclosures
   keeps 20rem for a list of year chips; /unclaimed sets 26rem in section 42
   because the Texas Property Code 76.506 paragraph has to read inside it. */
.page-layout {
  display: grid;
  gap: var(--space-6);
  align-items: start;
  grid-template-columns: minmax(0, 1fr);
}
/* Both, and not optional: without it a long unbroken value in either column
   sets that column's min-content and blows the grid past the viewport. */
.page-layout__main, .page-layout__aside { min-width: 0; }
@media (min-width: 1024px) {
  .page-layout { grid-template-columns: minmax(0, 1fr) var(--rail, 20rem); }
}
/* NOT sticky here. `.fc-aside` sets `position: sticky; top: var(--space-6)`,
   which parks that rail's top under the 152px pinned header — a latent bug on
   /foreclosures, out of scope for this pass, and NOT a precedent to copy. A
   page that wants a sticky rail must opt in AND prove its rail is shorter than
   the viewport minus the header. /unclaimed's is not; see section 42. */

/* ── 27. Pagination ─────────────────────────────────────────────────────── */

.pagination { display: flex; justify-content: center; margin-block: var(--space-6); }
.pagination ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  list-style: none;
  margin: 0; padding: 0;
}
.pagination a, .pagination [aria-current="page"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px; min-height: 44px;
  padding: 0 var(--space-3);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  font-weight: var(--fw-semibold);
}
.pagination a:hover { background: var(--cc-navy-light); border-color: var(--cc-navy-mid); }
.pagination [aria-current="page"] {
  background: var(--cc-navy);
  border-color: var(--cc-navy);
  color: var(--color-text-invert);
}

/* ── 28. Toasts (one live-region primitive — SPEC §8 Layer 0) ───────────── */

.toast-region {
  position: fixed;
  bottom: var(--space-5);
  left: 50%;
  transform: translateX(-50%);
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: min(92%, 26rem);
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--cc-navy-dark);
  color: var(--color-text-invert);
  border-left: 4px solid var(--cc-gold-bright);
  border-radius: var(--radius);
  box-shadow: var(--shadow-4);
  padding: var(--space-3) var(--space-4);
  animation: toast-in var(--transition-slow) var(--ease-out);
}
.toast--success { border-left-color: var(--cc-green); }
.toast--error { border-left-color: var(--cc-red); }
@keyframes toast-in {
  from { opacity: 0; transform: translateY(0.5rem); }
}

/* ── 29. Dialog ─────────────────────────────────────────────────────────── */

dialog {
  border: 0;
  border-radius: var(--radius);
  box-shadow: var(--shadow-4);
  padding: 0;
  width: min(92vw, 34rem);
  color: var(--color-text);
}
dialog::backdrop { background: var(--scrim-navy-soft); }
dialog[open] { animation: dlg-in 0.18s var(--ease-out); }
@keyframes dlg-in {
  from { opacity: 0; transform: translateY(0.4rem) scale(0.98); }
}
.dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  background: var(--cc-navy);
  color: var(--color-text-invert);
  padding: var(--space-4) var(--space-5);
}
.dialog__title { margin: 0; color: var(--color-text-invert); font-size: var(--fs-2); font-family: var(--font-ui); font-weight: var(--fw-bold); }
.dialog__close {
  border: 0;
  background: transparent;
  color: var(--color-text-invert);
  cursor: pointer;
  min-width: 40px; min-height: 40px;
  border-radius: var(--radius-sm);
}
.dialog__close:hover { background: var(--white-alpha-18); }
.dialog__body { padding: var(--space-5); }
.dialog__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}

/* ── 30. Footer ─────────────────────────────────────────────────────────── */

.site-footer { margin-top: 0; } /* .page-content's bottom padding provides the gap */

.footer-photo {
  position: relative;
  min-height: 260px;
  background:
    linear-gradient(180deg, var(--scrim-navy-soft), var(--scrim-navy)),
    var(--img-courthouse) center 40% / cover no-repeat,
    var(--cc-navy-dark);
  display: flex;
  align-items: flex-end;
  border-top: 4px solid var(--cc-gold);
}
.footer-photo__caption {
  width: 100%;
  color: var(--cc-gold-light);
  font-family: var(--font-display);
  padding-block: var(--space-4);
  margin: 0;
}

.site-footer__main {
  background: var(--grad-footer);
  color: var(--cc-navy-light);
  padding-block: var(--space-8);
}
.footer-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .footer-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .footer-grid { grid-template-columns: 2fr 1fr 1fr 1fr; }
}
.footer-brand img { filter: drop-shadow(0 2px 4px var(--shadow-color-deep)); }
.footer-brand__name {
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-2);
  color: var(--color-text-invert);
  margin: var(--space-2) 0;
}
.footer-brand__address { font-style: normal; line-height: var(--lh-body); }
.site-footer a { color: var(--cc-navy-light); }        /* on navy-dark ≥ 11:1 ✓ */
.site-footer a:hover { color: var(--cc-gold-bright); }
.footer-brand__social { margin-top: var(--space-3); }
.social-disc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  border-radius: var(--radius-full);
  background: var(--white-alpha-10);
  border: 1px solid var(--white-alpha-18);
  transition: background var(--transition), color var(--transition);
}
.social-disc:hover { background: var(--cc-gold-bright); color: var(--cc-navy-dark); }
.footer-col__heading {
  font-family: var(--font-ui);
  font-size: var(--fs-0);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cc-gold-bright);            /* on navy-dark 7.3:1 ✓ */
  margin-bottom: var(--space-3);
}
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-bottom: var(--space-2); }

.site-footer__bottom {
  background: var(--cc-navy-dark);
  border-top: 1px solid var(--white-alpha-18);
  color: var(--cc-navy-light);
  padding-block: var(--space-4);
}
.site-footer__bottom-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
}
.site-footer__bottom p { margin: 0; }
.site-footer__bottom-links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.site-footer__textmygov strong { color: var(--cc-gold-bright); }

/* ── 31. Reveal on scroll (enhancement; motion-safe) ────────────────────── */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity var(--transition-slow), transform var(--transition-slow);
}
.js [data-reveal].is-revealed { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* External-link icon added by public.js */
.external-icon { width: 0.85em; height: 0.85em; margin-left: 0.25em; vertical-align: baseline; }

/* ── 32. Reduced motion (WCAG 2.3.3) ────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  html { scroll-behavior: auto; }
  .hero__bg { animation: none; }
  .card:hover, .news-card:hover, .btn:hover, .doc-link:hover,
  .person-card:hover, .hero-chip:hover, .task-chip:hover,
  .mega-panel__featured:hover { transform: none; }
}

/* ── 33. Forced colors (Windows High Contrast) ──────────────────────────── */

@media (forced-colors: active) {
  .btn, .chip, .badge, .task-chip, .hero-chip {
    border: 1px solid CanvasText;
    forced-color-adjust: none;
    background: Canvas;
    color: LinkText;
  }
  .page-banner, .hero, .band-navy, .site-footer__main, .footer-photo {
    forced-color-adjust: auto;
  }
  :focus-visible { outline: 3px solid Highlight; outline-offset: 2px; box-shadow: none; }
  .alert-bar { border: 2px solid CanvasText; }
}

/* ── 34. Print ──────────────────────────────────────────────────────────── */

@media print {
  .skip-link, .utility-bar, .header-search, .primary-nav, .mobile-menu,
  .alert-bar__dismiss, .hero__search, .hero__chips, .toast-region,
  .footer-photo, .site-footer__bottom-links, .btn, .pagination { display: none !important; }
  .header-sticky { position: static; box-shadow: none; }
  .site-header, .page-banner, .band-navy, .site-footer__main, .site-footer__bottom {
    background: none !important;
    color: CanvasText;
  }
  .page-banner__title, .band-navy__title, .site-brand__name { color: CanvasText; }
  body { color: CanvasText; background: Canvas; }
  .page-content > .block { padding-inline: 0; }
  .prose a[href^="http"]::after, .doc-link[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
  }
  h1, h2, h3 { page-break-after: avoid; }
  .card, .news-card, .accordion__item, .table-scroll { box-shadow: none; }
  .accordion__item > .accordion__panel { display: block; }
}

/* ── 35. Containers & style presets (CMS-SPEC §7) ──────────── [P2-BLOCKS2] */
/* APPEND-ONLY. Nothing above this line was edited. Three families:
     .blk--*   per-block style presets  (block.style, §7)
     .sec--*   the `section` container  (blocks/section.js)
     .cols--*  the `columns` container  (blocks/columns.js)
   The vocabulary is CLOSED: every class here is emitted by
   blocks/util.js#presetClasses from an enum, never from author input, and
   every (tone x element) pairing is enumerated and proved >= WCAG AA by
   tools/contrast-check.mjs (npm run contrast-check). Adding a tone without
   adding its row to util.js TONE_SURFACES fails that check. */

/* ── 35.1 the preset wrapper ─────────────────────────────────────────────── */
/* renderBlocks wraps a styled block in <div class="block blk ...">. It carries
   `block` on purpose, so `.page-content > .block` (§10) keeps giving it the
   page column, the padding and the block-to-block rhythm — the wrapper takes
   over the layout role from the element it now wraps. */
.page-content > .blk--width-content { max-width: var(--content-width); }
.page-content > .blk--width-full,
.page-content > .blk:has(> .block--full) { max-width: none; padding-inline: 0; }
.page-content > .blk:has(> .block-hero-banner):first-child { margin-top: calc(-1 * var(--space-6)); }
.page-content:has(> .blk--width-full:last-child) { padding-bottom: 0; }

/* Spacing preset: vertical rhythm above and below the block. `normal` is the
   inherited `.block + .block` rhythm, so it declares nothing. */
.page-content > .blk--space-tight + .block,
.page-content > .block + .blk--space-tight { margin-top: var(--space-3); }
.page-content > .blk--space-loose + .block,
.page-content > .block + .blk--space-loose { margin-top: var(--space-10); }

.blk--align-center { text-align: center; }
.blk--align-center :is(.prose, .figure) { margin-inline: auto; }
.blk--align-end { text-align: end; }

.blk--divider-above { border-top: 1px solid var(--color-border); padding-top: var(--space-6); }
.blk--divider-below { border-bottom: 1px solid var(--color-border); padding-bottom: var(--space-6); }

/* A toned or carded block needs its own breathing room — text must never sit
   flush against the edge of the fill it is painted on. */
.blk--tone-muted, .blk--tone-navy, .blk--tone-gold-accent, .blk--tone-white-card {
  padding: var(--space-6) var(--space-5);
  border-radius: var(--radius);
}

/* ── 35.2 tones (the enumerated surfaces) ────────────────────────────────── */
.blk--tone-muted, .sec--tone-muted {
  background: var(--color-surface-tint);
  color: var(--color-text);
}
.blk--tone-gold-accent {
  background: var(--cc-gold-light);
  color: var(--color-text);
}
/* gray-600 loses too much on the pale gold fill; gray-700 keeps AA. */
.blk--tone-gold-accent :is(.figure figcaption, .figure-credit, .page-lede) { color: var(--cc-gray-700); }
.blk--tone-white-card {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-1);
}

/* Navy: the one INVERTED tone. Everything that carries its own colour has to
   be restated, or it inherits a light-on-light / dark-on-dark pairing. */
.blk--tone-navy, .sec--tone-navy {
  background: var(--color-surface-dark);
  color: var(--color-text-invert);
}
.blk--tone-navy :is(h1, h2, h3, h4, h5, h6),
.sec--tone-navy :is(h1, h2, h3, h4, h5, h6),
.sec--tone-navy > .sec__inner > .sec__title { color: var(--color-text-invert); }
.blk--tone-navy a, .sec--tone-navy a { color: var(--color-link-invert); }
.blk--tone-navy a:hover, .sec--tone-navy a:hover { color: var(--cc-gold-light); }
.blk--tone-navy :focus-visible, .sec--tone-navy :focus-visible { box-shadow: var(--focus-ring-dark); }
.blk--tone-navy :is(.figure figcaption, .figure-credit, .page-lede),
.sec--tone-navy :is(.figure figcaption, .figure-credit, .page-lede) { color: var(--color-text-invert); }
.blk--tone-navy hr, .sec--tone-navy hr { border-top-color: var(--white-alpha-35); }

/* LIGHT ISLANDS. A card, table, contact card or news row paints its OWN light
   surface, so inside a navy tone it would inherit white text on white — the
   exact WCAG 1.4.3 failure a closed palette exists to make impossible. The
   list is the closed set of light-surface components the 20 block renderers
   can emit; a new block that paints a light surface adds itself here. */
.blk--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card),
.sec--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) { color: var(--color-text); }
.blk--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) :is(h1, h2, h3, h4, h5, h6),
.sec--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) :is(h1, h2, h3, h4, h5, h6) { color: var(--color-heading); }
.blk--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) a,
.sec--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) a { color: var(--color-link); }
.blk--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) :focus-visible,
.sec--tone-navy :is(.card, .contact-card, .accordion__item, .table-scroll,
                    .doc-list, .quicklink-row, .news-card, .event-row,
                    .meeting-next, .fact-card) :focus-visible { box-shadow: var(--focus-ring); }

/* ── 35.3 the `section` container ────────────────────────────────────────── */
.sec__inner { margin-inline: auto; }
.sec__body > .block + .block { margin-top: var(--space-6); }
.sec__title + .sec__body { margin-top: var(--space-5); }

.sec--width-content .sec__inner { max-width: var(--content-width); }
.sec--width-wide .sec__inner { max-width: none; }
/* Only a FULL-width section escapes the page column, so only it re-creates
   the container padding its parent no longer supplies. */
.sec--width-full .sec__inner {
  max-width: var(--max-width);
  padding-inline: var(--container-pad);
}
.sec--tone-muted, .sec--tone-navy {
  padding-block: var(--space-7);
  padding-inline: var(--space-5);
  border-radius: var(--radius);
}
.sec--width-full:is(.sec--tone-muted, .sec--tone-navy) {
  padding-block: var(--section-pad);
  padding-inline: 0;
  border-radius: 0;
}

/* ── 35.4 the `columns` container ────────────────────────────────────────── */
/* One column at every width by default; `stackAt` says where the tracks
   appear. minmax(0, 1fr) — a bare 1fr track's min-size is `auto`, which lets
   a long token blow the track past a 320 px viewport (WCAG 1.4.10). */
.cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
}
.cols--gap-loose { gap: var(--space-8); }
.cols--valign-center { align-items: center; }
.cols__col { min-width: 0; }
.cols__col > .block + .block { margin-top: var(--space-5); }

/* A GRID INSIDE A COLUMN IS A LIST. The card, people and image-text grids
   choose their track count from the VIEWPORT width (§13, §14) because until
   now nothing could make a block narrower than the page column. Inside a
   column they keep asking for three or four tracks and the result is a 187 px
   card breaking "County Clerk" mid-word — measured, at 1280 px, in a two-
   column section. One track per column is the honest answer: it can never
   overflow and it never breaks a word, at any viewport, at any zoom. */
.cols__col :is(.card-grid, .people-grid, .image-text) {
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 480px) {
  .cols--stack-sm.cols--count-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cols--stack-sm.cols--count-3,
  .cols--stack-sm.cols--count-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cols--stack-sm.cols--count-2.cols--ratio-wide-left { grid-template-columns: 2fr minmax(0, 1fr); }
  .cols--stack-sm.cols--count-2.cols--ratio-wide-right { grid-template-columns: minmax(0, 1fr) 2fr; }
}
@media (min-width: 768px) {
  .cols--stack-md.cols--count-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cols--stack-md.cols--count-3,
  .cols--stack-md.cols--count-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cols--stack-md.cols--count-2.cols--ratio-wide-left { grid-template-columns: 2fr minmax(0, 1fr); }
  .cols--stack-md.cols--count-2.cols--ratio-wide-right { grid-template-columns: minmax(0, 1fr) 2fr; }
}
/* The compound `.cols--stack-*.cols--count-*` selectors above are (0,2,0);
   a bare `.cols--count-3` here would be (0,1,0) and LOSE on specificity even
   though it comes later — three columns would silently stay two forever.
   `:is()` takes the specificity of its most specific argument, so this is
   (0,2,0) too, and source order decides as intended. */
@media (min-width: 1024px) {
  :is(.cols--stack-sm, .cols--stack-md).cols--count-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  :is(.cols--stack-sm, .cols--stack-md).cols--count-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ── 35.5 reduced motion / forced colors / print ─────────────────────────── */
@media (forced-colors: active) {
  .blk--tone-navy, .sec--tone-navy,
  .blk--tone-muted, .sec--tone-muted,
  .blk--tone-gold-accent, .blk--tone-white-card { forced-color-adjust: auto; }
  .blk--tone-white-card { border: 1px solid CanvasText; }
}
@media print {
  .page-content > .blk { padding-inline: 0; }
  .blk--tone-navy, .sec--tone-navy,
  .blk--tone-muted, .sec--tone-muted,
  .blk--tone-gold-accent, .blk--tone-white-card {
    background: none !important;
    color: CanvasText;
    box-shadow: none;
  }
  .blk--tone-navy :is(h1, h2, h3, h4, h5, h6), .sec--tone-navy :is(h1, h2, h3, h4, h5, h6),
  .blk--tone-navy a, .sec--tone-navy a { color: CanvasText; }
  .cols { display: block; }
  .cols__col + .cols__col { margin-top: var(--space-5); }
}

/* ════════════════════════════════════════════════════════════════════════════
   36–40. THE FOUR ROUTE RENDERERS AND THE ONE CMS BLOCK THAT SHIPPED WITH NO
   STYLESHEET AT ALL                                        [MODULE F2 part 1]

   FULL-REVIEW §5.3 / audits/ux-visual.md V-01, V-03, V-04, V-12, V-14.

   These class families are NOT legacy. Nothing was lost in migration: the
   county's own new server-side code emits them and a matching stylesheet was
   never written, so `/documents`, `/foreclosures`, the FAQ and `/search`
   rendered as raw browser defaults on a site whose every other page is
   finished work. Four separate route files and one first-class CMS block,
   four separate times nobody noticed — which is why tools/css-coverage.mjs
   now fails a build when a renderer emits a class with no rule.

   Everything below is built from the SAME primitives as the rest of the file:
   `.card` for boxes, `.data-table` for tables, `.chip` for filters,
   `.accordion` for disclosure, `.doc-link` for document rows, the `.btn`
   variants for actions, and colour exclusively from tokens.css. The point is
   not that these pages get A design — it is that they get THIS design.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 36. Document Center — routes/files-public.js ──────────────────────────
   `/documents` and every folder depth on both hosts. */

.doc-center > * + * { margin-top: var(--space-6); }

/* The search control the Document Center, the foreclosure page and the
   collection-list block all render. One row, input grows, button never wraps
   under 44px. `flex-wrap` so the button drops below the field at 320px
   instead of squeezing it to nothing. */
.doc-search, .cl-search {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin: 0;
}
.doc-search input[type="search"], .cl-search input[type="search"] {
  flex: 1 1 18rem;
  min-width: 0;
  width: auto;
}
.doc-search .btn, .cl-search .btn { flex: none; }

/* Folder cards. The bug that made this page look broken is one missing
   declaration: `.card` is applied to an <a>, and an anchor is inline by
   default, so the box painted an empty inline rectangle and its heading and
   paragraphs escaped out from under it (V-01, "a small empty bordered
   rectangle floating above every entry"). `display: block` on the link
   variant is the fix; the grid is what turns 8 stacked links into a browser. */
.card--link { display: block; }

.doc-folder-grid {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--space-4);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 480px) { .doc-folder-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .doc-folder-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.doc-folder-card { min-width: 0; }
.doc-folder-card .card--link {
  height: 100%;
  border-top: 3px solid var(--cc-gold);
  text-decoration: none;
}
/* Name / description / count were three separately underlined blue links
   stacked on each other. Only the NAME is the link's title; the other two are
   supporting text and must not wear link ink. */
.doc-folder-card__name {
  font-family: var(--font-ui);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  color: var(--cc-navy);
  margin: 0 0 var(--space-2);
  overflow-wrap: anywhere;
}
.doc-folder-card__desc {
  margin: 0 0 var(--space-3);
  color: var(--color-text);      /* 15.4:1 ✓ */
}
.doc-folder-card__meta {
  margin: 0;
  color: var(--cc-gray-700);     /* 10.0:1 ✓ — well above the AA floor */
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.doc-folder-card .card--link:hover .doc-folder-card__name { text-decoration: underline; }

/* File table. The renderer now stamps `.data-table` alongside `.doc-table`, so
   the header band, striping, borders and hover come from ONE definition
   (§17) and only the deltas live here.
   `th[scope=row]` is the defect residents actually saw: the browser default is
   `text-align:center; font-weight:bold`, so 76 filenames zig-zagged down the
   page with ragged left AND right edges. §17 already left-aligns
   `.data-table th`; this restates the weight because a filename is data, not
   a heading, and it is the widest column on the page. */
.doc-table { table-layout: auto; }
.doc-table th[scope="row"] {
  text-align: left;
  font-weight: var(--fw-regular);
  background: transparent;
  width: 60%;
  overflow-wrap: anywhere;
}
.doc-table tbody tr:nth-child(even) th[scope="row"] { background: var(--color-surface-tint); }
.doc-table th[scope="row"] a { font-weight: var(--fw-semibold); }
.doc-table td { white-space: nowrap; }
.doc-table td:first-of-type { white-space: normal; }
.doc-table__folder {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-meta);
  color: var(--cc-gray-700);     /* 10.0:1 ✓ */
}

.doc-count {
  margin: 0;
  font-weight: var(--fw-semibold);
  color: var(--cc-gray-700);     /* 10.0:1 ✓ */
}
.doc-feed-link { margin: 0; }

/* ── 37. Foreclosure notices — routes/foreclosures.js ──────────────────────
   Statutory postings under Texas Property Code § 51.002. */

.fc-page > * + * { margin-top: var(--space-6); }

/* The grid itself is `.page-layout` in section 26 now — this page was where it
   was first worked out, and /unclaimed is the second user, so it stopped being
   a page concern. The markup carries both class names; what is left here is
   only what /foreclosures does differently, which is its 20rem default rail
   (the shared component's `--rail` fallback) and its own rhythm. The year rail
   was once stacked BELOW 44,400px of notices and therefore unreachable
   (V-04) — that fix now lives in the shared rule. */
.fc-main > * + * { margin-top: var(--space-6); }
@media (min-width: 1024px) { .fc-aside { position: sticky; top: var(--space-6); } }

.fc-card > :first-child { margin-top: 0; }
.fc-card > :last-child { margin-bottom: 0; }
.fc-card > * + * { margin-top: var(--space-4); }
.fc-card h2 { font-size: var(--fs-3); margin-bottom: 0; }
.fc-help { color: var(--color-text); margin: 0; }
/* .fc-note now lives in section 15 as `.note-strip, .fc-note` — one rule,
   two names, so this page renders byte-identically and needs no markup change. */
.fc-aside address { font-style: normal; margin: 0; }

.fc-month + .fc-month { margin-top: var(--space-7); }
.fc-month > h3 {
  font-size: var(--fs-3);
  margin-bottom: var(--space-4);
}

/* THE notice row. `.doc-list` caps itself at 60rem, which left a 247px dead
   gutter down the right of every row inside a 1,232px card (V-04); inside the
   foreclosure column the list IS the content, so it fills its column.
   The other half of V-04: the renderer puts "Sale date: …" in a sibling
   <span> AFTER the <a>, so with `.doc-link` carrying the border the card's
   bottom edge cut between a notice and its own sale date. Moving the border
   onto the <li> makes the whole entry one card, with no markup change —
   which matters, because the date must stay OUT of the link text (a link
   named "8-4-26 Fohn (PDF, 779 KB) Sale date: Tuesday, August 4, 2026" is a
   worse accessible name, WCAG 2.4.4). */
.fc-list { max-width: none; }
.fc-list .doc-item {
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: var(--radius);
  background: var(--color-surface);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.fc-list .doc-item + .doc-item { margin-top: var(--space-3); }
.fc-list .doc-item:hover { border-left-color: var(--cc-gold); box-shadow: var(--shadow-1); }
.fc-list .doc-link {
  border: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  padding-bottom: var(--space-1);
  transform: none;
}
.fc-list .doc-link:hover { transform: none; box-shadow: none; }
.fc-sale-date {
  display: block;
  padding: 0 var(--space-4) var(--space-3);
  color: var(--cc-gray-700);     /* 10.0:1 ✓ */
  font-size: var(--fs-0);
}
.fc-sale-date time { font-weight: var(--fw-semibold); }

/* Year filter + search-type filters share the chip vocabulary (§26). They are
   links rather than buttons, so the pressed state is `aria-current`. */
.fc-years, .search-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0; padding: 0;
}
/* `li` is in the selector for specificity, not for structure: the year chips
   sit inside `<section class="card fc-card">`, and §1's `.card li a` (0,1,2)
   out-specifies a bare `.fc-years a` (0,1,1) — the chips came out underlined
   with the pill drawn around the underline. */
.fc-years li a, .search-chips li a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-link);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}
.fc-years li a:hover, .search-chips li a:hover { background: var(--cc-navy-light); }
.fc-years li a[aria-current], .search-chips li a[aria-current] {
  background: var(--cc-navy);
  border-color: var(--cc-navy);
  color: var(--color-text-invert);   /* 11.6:1 ✓ */
}

/* ── 38. Collection list block — services/blocks/collection-list.js ────────
   Five layouts, one for each shape of record the CMS publishes: the staff
   directory, the FAQs, the open bids, the notices, the facilities. The
   `collections` feature flag is ON in production, so ANY collection-list
   block placed anywhere on either host was rendering raw (V-03). */

.cl-heading { font-size: var(--fs-4); }

/* The five layout modifiers. The renderer stamps `cl--<layout>` on the block
   wrapper for every one of them and not one carried a rule — which is exactly
   how a first-class CMS block came to ship with no stylesheet and nobody
   noticed, so these are not decoration.
   Each layout's own vertical rhythm lives here, on the element that knows
   which layout it is: `cards` and `table` are heavy, self-contained objects
   and take a full step between the heading, the search field and the list;
   `accordion`, `list` and `compact` are internally ruled and read as one
   object, so a full step between their parts makes them look like three
   unrelated blocks instead of one. */
.cl--cards > * + *,
.cl--table > * + * { margin-top: var(--space-5); }
.cl--accordion > * + *,
.cl--list > * + *,
.cl--compact > * + * { margin-top: var(--space-4); }
.cl-empty {
  margin: 0;
  color: var(--color-text-muted);
  background: var(--color-surface-tint);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
}
.cl-all { margin: 0; }
.cl-all a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--fw-semibold);
}

/* cards */
.cl-cards {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--space-4);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 480px) { .cl-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .cl-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.cl-card {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-top: 3px solid var(--cc-gold);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
  transition: transform var(--transition), box-shadow var(--transition);
}
.cl-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.cl-card__title {
  font-family: var(--font-ui);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  margin: 0;
  overflow-wrap: anywhere;
}
.cl-card__title a { text-decoration: none; }
.cl-card__title a:hover { text-decoration: underline; }
.cl-card__summary { margin: 0; color: var(--color-text); }
.cl-card__meta {
  margin: auto 0 0;
  padding-top: var(--space-2);
  color: var(--cc-gray-700);     /* 10.0:1 ✓ */
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* list */
.cl-list { list-style: none; margin: 0; padding: 0; }
.cl-row {
  display: block;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: var(--radius);
  background: var(--color-surface);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.cl-row + .cl-row { margin-top: var(--space-2); }
.cl-row:hover { border-left-color: var(--cc-gold); box-shadow: var(--shadow-1); }
.cl-row__title {
  display: block;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-1);
  overflow-wrap: anywhere;
}
/* Title and summary were adjacent inline spans — the same jam that makes
   legacy rows read "Phone(512) 398-1808". A summary is its own line. */
.cl-row__summary {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-text);
}

/* compact — names only, in columns */
.cl-compact {
  list-style: none;
  margin: 0; padding: 0;
  columns: 2 14rem;
  column-gap: var(--space-6);
}
.cl-compact li { break-inside: avoid; margin-bottom: var(--space-2); }

/* table — the renderer stamps `.data-table` alongside, so §17 supplies the
   header band and striping. */
.cl-table th[scope="row"] { font-weight: var(--fw-semibold); }
.cl-table caption { caption-side: top; }

/* accordion — the FAQ. Two disclosure indicators per row (the browser's own
   ▶ marker AND the drawn chevron, pointing different directions) is the whole
   of V-03's visible symptom; `list-style: none` on the summary removes the
   native one in every engine, and the -webkit- pseudo covers older Safari. */
.cl-acc { display: block; }
.cl-acc__item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  box-shadow: var(--shadow-1);
}
.cl-acc__item + .cl-acc__item { margin-top: var(--space-3); }
.cl-acc__item > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  list-style: none;
  cursor: pointer;
  padding: var(--space-4) var(--space-5);
  min-height: 48px;
  font-weight: var(--fw-semibold);
  color: var(--cc-navy);
  border-radius: var(--radius);
}
.cl-acc__item > summary::-webkit-details-marker { display: none; }
.cl-acc__item > summary::marker { content: ""; }
.cl-acc__item > summary:hover { background: var(--color-surface-tint); }
.cl-acc__q { min-width: 0; }
.cl-acc__chev { color: var(--cc-gold-text); flex: none; transition: transform var(--transition); }
.cl-acc__item[open] > summary { border-bottom: 1px solid var(--color-border); border-radius: var(--radius) var(--radius) 0 0; }
.cl-acc__item[open] > summary .cl-acc__chev { transform: rotate(180deg); }
.cl-acc__a { padding: var(--space-4) var(--space-5); }
.cl-acc__a > :first-child { margin-top: 0; }
.cl-acc__a > :last-child { margin-bottom: 0; }

/* ── 39. Search results page — routes/search.js ────────────────────────────
   The page reachable from the header search box on all 137 pages. It used to
   build its own bare document with ~1KB of inline CSS: no utility bar, no
   seal, no nav, no breadcrumb, no footer, and an 832px column centred at
   x=244 where every other page on the site is a left-aligned grid at x=24
   (V-12). The route now goes through renderShell() like every other feature
   route, so the chrome is the real chrome and these rules are only the
   results list. */

.search-page > * + * { margin-top: var(--space-5); }
.search-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}
.search-form input[type="search"] { flex: 1 1 20rem; min-width: 0; width: auto; }
.search-form .btn { flex: none; }

.search-summary {
  margin: 0;
  font-size: var(--fs-1);
  color: var(--color-text);
}
.search-results { list-style: none; margin: 0; padding: 0; }
.search-result { padding-block: var(--space-4); border-top: 1px solid var(--color-border); }
.search-result:first-child { border-top: 0; padding-top: 0; }
.search-result-meta {
  margin: 0 0 var(--space-1);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  font-size: var(--fs-meta);
  color: var(--cc-gray-700);     /* 10.0:1 ✓ */
}
.search-result-type {
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--cc-gold-text);    /* 6.3:1 ✓ */
}
.search-result-title {
  font-family: var(--font-ui);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  margin: 0 0 var(--space-1);
  overflow-wrap: anywhere;       /* extracted document text has no word breaks */
}
.search-result-format { font-weight: var(--fw-semibold); color: var(--cc-gray-700); }
.search-result-snippet { margin: 0; overflow-wrap: anywhere; }
/* The default <mark> is the browser's bright yellow, which clashes with both
   the navy/gold and the emerald palettes. `--cc-navy-light` is re-pointed to
   emerald-light under `.site-elections`, so ONE rule themes both hosts.
   Body text on it: 10.1:1 ✓ */
.search-result-snippet mark, .search-page mark {
  background: var(--cc-navy-light);
  color: var(--color-text);
  font-weight: var(--fw-bold);
  padding: 0 0.15em;
  border-radius: var(--radius-sm);
}
.search-empty > :last-child { margin-bottom: 0; }
.search-empty ul { margin-bottom: 0; }
.search-paging {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}
.search-paging span { color: var(--cc-gray-700); font-weight: var(--fw-semibold); }

/* Header search input: tab stop 8 on all 137 pages, and the ONE control in the
   header that showed nothing on :focus-visible — `outline-style:none` with a
   fully transparent box-shadow (V-15, WCAG 2.4.7). The header sits on the navy
   gradient, so it takes the dark-surface ring like its neighbours. */
.header-search input:focus-visible,
.mobile-menu__search input:focus-visible { box-shadow: var(--focus-ring-dark); }

/* ── 40. Jobs board — routes/jobs.js ───────────────────────────────────────
   `.jobs-board` was a dead class on `.page-content`. Two real defects (V-14):
   the results card did not fill its 940px column, leaving 478px of empty
   grid; and `.filter-layout` had no bottom margin, so "Why work for Caldwell
   County?" began at the exact pixel the filter rail ended. */

.jobs-board .filter-layout { margin-bottom: var(--space-8); }
/* auto-fit collapses the empty tracks, so ONE open posting fills the column
   and two or more still sit side by side. `min(100%, 20rem)` keeps the track
   from exceeding the column at 320px. */
.jobs-board .filter-layout .card-grid {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
}

/* ── 40.1 County calendar month grid — routes/events.js ────────────────────
   Not one of the four families audits/ux-visual.md named, because the month
   grid stamps `data-table` and therefore inherits §17 and looks broadly
   right. tools/css-coverage.mjs found the rest of the route's own classes
   with no rule, and one of them is load-bearing: `.cal-today` is how a
   resident finds today in a 35-cell grid, and it had no rule at all. The
   renderer's only other marker for it is a `.visually-hidden` "(today)" —
   correct for a screen reader, invisible to everyone else. */

.cal-day { font-variant-numeric: tabular-nums; }
/* Today: gold rule + weight, never colour alone (WCAG 1.4.1). The tint is the
   same one §17 uses for a hovered row, so the grid keeps one vocabulary. */
.cal-today {
  background: var(--color-surface-tint);
  box-shadow: inset 0 -3px 0 var(--cc-gold);
}
.cal-today .cal-day { font-weight: var(--fw-bold); color: var(--cc-navy); }
/* Leading and trailing cells that belong to the neighbouring month. They are
   empty, so they must read as "not part of this month" without drawing the
   eye — a wash below the striping, no text, no border change. */
.cal-empty { background: var(--cc-gray-100); }

/* ── 40.2 Route section wrappers ───────────────────────────────────────────
   The last two classes tools/css-coverage.mjs reports with no rule, both
   `<section>` roots a feature route stamps around a stack of six children:
   `.meetings-archive` (routes/meetings.js:631) holds the section head, the
   search toolbar, the year chips, the result count, the archive table and the
   pager; `.cal-list` (routes/events.js:288) holds the month heading and the
   month's event list.

   They are not decoration. Every other route root in this file — `.doc-center`,
   `.fc-page`, `.fc-main`, `.search-page` — owns its own vertical rhythm, and
   these two owned none, so their children were spaced only by whatever margin
   each happened to carry: measured on /meetings at 1280, `.doc-count` ("544
   meeting records…") sat at a **0 px** gap against the top of the archive
   table, reading as a table caption rather than as the count of what follows.
   Adjacent margins collapse, so this sets a floor rather than adding to the
   24 px the section head and toolbar already carry.

   SCOPE NOTE: this is spacing INSIDE the section only. The missing page
   gutter on /calendar, /news, /plats and /meetings (ux-visual.md V-02 —
   these sections are direct children of `.page-content` without `.block`, so
   they get no `max-width`, no centring and no `--container-pad`) is
   FULL-REVIEW P1-15 and is deliberately NOT fixed here: half of each page
   would move and half would not. */
.meetings-archive > * + *,
.cal-list > * + * { margin-top: var(--space-5); }

/* ════════════════════════════════════════════════════════════════════════════
   41. LEGACY `block-html` COMPATIBILITY LAYER (SPEC §13.4) [MODULE F2 part 2]

   FULL-REVIEW §5.3 / audits/ux-visual.md V-05, V-08, V-09, V-10, V-11, V-18.

   57 of 137 pages carry migrated vendor markup in an `html` block. That markup
   references a stylesheet that was never migrated, so 128 class names had zero
   rules and the pages fell back to whatever the browser does with a <div>:
   label and value became adjacent inline spans one space apart and residents
   read "Phone(512) 398-1808", "Divorce / Adoption / Civil$350.00",
   "Certified Seal$5.00"; 290 calls to action across 47 pages — including
   "Sign Up Now →" for WarnCentralTexas emergency alerts — rendered as plain
   underlined text; the Sanitation task router, the best wayfinder on the site,
   collapsed into one run-on paragraph; and the Sheriff's "Emergency" heading
   sat navy-on-dark-red at 1.16:1 directly above the number 911.

   THE RULES OF THIS SECTION
   1. EVERY selector is scoped to `.block-html`. Nothing here can reach a
      designed block, and deleting the whole section restores today's output
      exactly. This is the stop-gap the SPEC §13.4 cleanup pass replaces when
      the markup is re-authored as real blocks — not a second design system.
   2. It re-uses the primitives above rather than inventing new looks, so a
      compat card is the same card, a compat button is a token-validated
      button, and a compat table is the same table.
   3. It changes NO content. Every fix is presentational: the label/value
      markup is already correct HTML, it simply had no layout.
   4. Colour comes only from tokens.css, and every text/background pairing is
      annotated with its measured ratio.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 41.1 Page layouts ────────────────────────────────────────────────────
   `content-grid` (40 pages) is the vendor's main+sidebar shell. Its children
   had no tracks, so the sidebar sat under the article at every width. */

.block-html .content-grid,
.block-html .two-col-layout,
.block-html .responsive-grid-1col {
  display: grid;
  gap: var(--space-6);
  align-items: start;
  grid-template-columns: minmax(0, 1fr);
}
.block-html .content-main, .block-html .content-sidebar { min-width: 0; }
.block-html .content-main > * + * { margin-top: var(--space-5); }
.block-html .content-sidebar > * + * { margin-top: var(--space-4); }
@media (min-width: 1024px) {
  .block-html .content-grid { grid-template-columns: minmax(0, 1fr) 20rem; }
}
/* These two carry an inline `grid-template-columns` (2fr 1fr / 1fr 320px) that
   is right on a desktop and impossible on a phone, and an inline declaration
   can only be beaten by !important. The existing 480px blanket rule is not
   enough: a 2fr/1fr split is already unreadable at 768px. */
@media not all and (min-width: 1024px) {
  .block-html .two-col-layout,
  .block-html .responsive-grid-1col { grid-template-columns: minmax(0, 1fr) !important; }
}

/* Card / tile grids. Every one of these was a stack of full-width divs. */
.block-html :is(.info-grid, .division-grid, .resource-grid, .about-grid,
                .gallery-grid, .hr-doc-grid, .hr-year-grid, .feature-grid,
                .kit-grid, .cp-cols, .sd-form-list, .sd-steps,
                .sd-task-finder, .prea-grid) {
  display: grid;
  gap: var(--space-4);
  align-items: start;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 480px) {
  .block-html :is(.info-grid, .division-grid, .resource-grid, .gallery-grid,
                  .hr-doc-grid, .hr-year-grid, .feature-grid, .kit-grid,
                  .cp-cols, .sd-form-list, .sd-steps, .sd-task-finder) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 768px) {
  .block-html :is(.info-grid, .division-grid, .resource-grid, .gallery-grid,
                  .cp-cols, .sd-task-finder) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .block-html .feature-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .block-html .kit-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .block-html .about-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .block-html .prea-grid { grid-template-columns: 18rem minmax(0, 1fr); }
  .block-html .sd-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .block-html .about-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .block-html .sd-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .block-html .hr-year-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* `align-items: start` above is right for a grid of prose columns, where a
   short column should not be padded out to match a long one. It is wrong for
   a row of BOXES: a box that stops short of its neighbours reads as unfinished
   rather than as short. Measured on /departments/sanitation, the four permit
   steps came out 205 / 205 / 284 / 230px tall — one numbered process, four
   different bottom edges. Boxes stretch; `.about-grid`, `.prea-grid`,
   `.cp-cols` and the gallery stay on `start`, because those really are
   columns. `a.sd-task` reaches the same result with `height: 100%`. */
.block-html :is(.sd-steps, .info-grid, .division-grid, .resource-grid,
                .feature-grid, .kit-grid, .hr-doc-grid) { align-items: stretch; }
.block-html .about-col { min-width: 0; }
.block-html .about-col--quotes > * + * { margin-top: var(--space-4); }
.block-html .gallery-grid figure { margin: 0; }
.block-html .gallery-grid img { border-radius: var(--radius); display: block; width: 100%; }
.block-html .gallery-grid figcaption {
  margin-top: var(--space-2);
  color: var(--cc-gray-700);              /* 10.0:1 ✓ */
}
.block-html .prea-poster { border-radius: var(--radius); box-shadow: var(--shadow-2); width: 100%; }

/* ── 41.2 Boxes: cards, panels, tiles ─────────────────────────────────────
   One card definition, applied to the nine names the vendor markup uses. */

.block-html :is(.info-card, .service-card, .sidebar-card, .sidebar-box,
                .info-block, .location-card, .resource-card, .cp-col-card,
                .cp-toc, .division-card, .feature-tile, .stat-tile,
                .service-tile, .court-schedule, .sd-form-group, .hr-eoe) {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
  min-width: 0;
}
.block-html :is(.info-card, .service-card, .sidebar-card, .sidebar-box,
                .info-block, .location-card, .resource-card, .cp-col-card,
                .cp-toc, .division-card, .service-tile) > :first-child { margin-top: 0; }
.block-html :is(.info-card, .service-card, .sidebar-card, .sidebar-box,
                .info-block, .location-card, .resource-card, .cp-col-card,
                .cp-toc, .division-card, .service-tile) > :last-child { margin-bottom: 0; }
/* A card inside a card is one border too many — on /residents/.../crisis-hotlines
   the whole hotline table is an `.info-card` nested in a `.card`. */
.block-html .card :is(.info-card, .sidebar-card, .info-block) {
  border: 0; box-shadow: none; padding: 0; background: none;
}
.block-html :is(.sidebar-card, .sidebar-box, .cp-sidebar-card, .info-block) h3 {
  font-size: var(--fs-2);
  margin-bottom: var(--space-3);
}
.block-html :is(.division-card, .resource-card, .location-card, .cp-col-card) h3,
.block-html .service-tile h3 { font-size: var(--fs-2); }
.block-html :is(.service-card, .info-card) { display: flex; flex-direction: column; padding: 0; }
.block-html :is(.service-card, .info-card) > :is(.service-card-body, .info-card-body) { flex: 1; }

/* Header bands. The vendor stylesheet painted these; without it a band was an
   ordinary line of text — and on /government/sheriff the "Emergency" card
   kept its inline dark-red background (hex 8b0000) while its <h3> kept the navy
   heading colour, giving 1.16:1 on the card that carries 911 (V-09).
   White on that same dark red is 10.0:1, so inverting the band text fixes the
   contrast without overriding a single byte of the page's own content. */
.block-html :is(.card-header, .service-card-header) {
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* on navy 11.6:1 ✓ · on hex 8b0000 10.0:1 ✓ */
  font-family: var(--font-ui);
  font-weight: var(--fw-bold);
  font-size: var(--fs-2);
  line-height: var(--lh-tight);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius) var(--radius) 0 0;
}
.block-html :is(.card-header, .service-card-header) :is(h2, h3, h4) {
  color: inherit;
  font-family: inherit;
  font-size: inherit;
  margin: 0;
}
/* The Fire Departments band on /departments/emergency-management asked for red
   and got nothing. White on red-dark is 10.4:1. */
.block-html .service-card-header.red-header { background: var(--cc-red-dark); }
.block-html :is(.service-card-body, .card-body-legacy) { padding: var(--space-5); }
.block-html .service-card-body > :first-child { margin-top: 0; }
.block-html .service-card-body > :last-child { margin-bottom: 0; }
.block-html :is(.service-card-footer, .info-card-footer) {
  padding: 0 var(--space-5) var(--space-5);
  margin-top: auto;
}
/* A `.card` that carries a band must let the band reach its own edges. */
.block-html .card:has(> .card-header) { padding: 0; overflow: hidden; }
.block-html .card:has(> .card-header) > .card-body { padding: var(--space-5); }

.block-html .info-card-header {
  background: var(--cc-navy-light);
  color: var(--cc-navy);                  /* 10.1:1 ✓ */
  font-family: var(--font-ui);
  font-weight: var(--fw-bold);
  font-size: var(--fs-1);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius) var(--radius) 0 0;
  border-bottom: 1px solid var(--color-border);
}
.block-html .info-card-body { padding: var(--space-5); }
/* The Sheriff's public-safety cards put bare <a> elements in a run with only
   <br> between them, so a resident could not tell which items were links and
   which were plain text (V-10). Each link becomes its own row. */
.block-html .info-card-body > a {
  display: block;
  padding-block: var(--space-1);
  font-weight: var(--fw-semibold);
}

/* Sidebar cards keep the vendor's left accent where the markup asks for one. */
.block-html .sidebar-card, .block-html .cp-sidebar-card {
  border-left: 4px solid var(--cc-navy-mid);
}
.block-html .cp-sidebar-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
}
.block-html .cp-sidebar-card + .cp-sidebar-card { margin-top: var(--space-4); }
.block-html .cp-sidebar-card p { margin-bottom: var(--space-2); }

/* Whole-tile links must not read as prose links. */
.block-html a.service-tile { display: block; text-decoration: none; }
.block-html a.service-tile:hover { box-shadow: var(--shadow-3); border-color: var(--cc-gold); }

/* ── 41.3 Label / value rows — THE defect Chris reported ──────────────────
   804 uses across 35 pages. `<span class="info-label">Phone</span><span
   class="info-value">(512) 398-1808</span>`: correct HTML, no layout, so the
   two spans sat one space apart and read as one word. A two-column grid is
   the whole fix; it collapses to stacked pairs on a phone, where a 12rem
   label column would leave nothing for the value. */
.block-html .info-row {
  display: grid;
  grid-template-columns: minmax(0, min(13rem, 40%)) minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  align-items: baseline;
  padding-block: var(--space-3);
  border-top: 1px solid var(--color-border);
}
.block-html .info-row:first-child, .block-html .info-card > .info-row:first-child { border-top: 0; }
.block-html .info-label {
  font-weight: var(--fw-semibold);
  color: var(--cc-gray-700);              /* 10.0:1 ✓ — a label is not fine print */
}
.block-html .info-value { min-width: 0; overflow-wrap: anywhere; }

/* THE SECOND HALF OF THIS FIX, and it is not optional.
   A label/value row is not always in a full-width box. The vendor markup puts
   these rows inside cards that are themselves laid out 2-, 3- and 4-up by an
   inline `grid-template-columns: repeat(4, 1fr)`, and the width that reaches
   the row is then a fraction of the page, not the page.

   With a FIXED 13rem label track that is fatal, and measured, not theorised:
   on /government/commissioners-court at 1280 each precinct card is ~240px, the
   label track took 208px of it, the value column was left **9px**, and
   `overflow-wrap: anywhere` (correct, and needed for the long e-mail addresses
   in the very same rows) then wrapped every commissioner's phone number to ONE
   CHARACTER PER LINE. Sitewide sweep of all 119 published pages: 5 pages at
   1280 (commissioners-court, constables, justice-of-the-peace, district-courts,
   justice-center) and 10 pages at 768. A viewport media query cannot see any of
   it — the viewport is 1280px wide; the box is not.

   Two independent guards, because this must not come back:

   1. The track cap above is `min(13rem, 40%)`. The label can never take more
      than 40% of whatever box it lands in, so the value keeps at least 60%
      whether or not container queries are supported. At an 880px card
      `min()` still resolves to 13rem, so every wide row renders exactly as
      before this line was written.
   2. Below 26rem of CONTAINER width the pair stacks outright, which is what a
      240px card actually needs. Same treatment the 480px viewport query
      already applies on a phone — the trigger is just measured in the right
      coordinate system.

   `container-type` is applied only to the eight wrappers that actually hold
   these rows (enumerated from the rendered DOM of all 119 pages, not guessed).
   All 119 were swept for absolutely-positioned or content-width-sized
   descendants first, because `container-type` implies `contain: layout`: there
   are none, so nothing re-anchors and nothing collapses. `:has()` is already
   relied on above (§41.2), so this is inside the file's existing baseline. */
.block-html :is(.info-card, .card, .card-body, .staff-list,
                .location-card, .sidebar-box, .court-schedule,
                .service-card-body) { container-type: inline-size; }

@media (max-width: 480px) {
  .block-html .info-row { grid-template-columns: minmax(0, 1fr); }
  .block-html .info-label { font-size: var(--fs-meta); text-transform: uppercase; letter-spacing: 0.05em; }
}

/* Five rows in the STEAR sidebar on /departments/emergency-management carry
   an inline `flex-direction:column; gap:.15rem` — the author asking the
   vendor's flex row to STACK, because the rail is too narrow for two columns.
   `flex-direction` is inert on a grid, but the inline `gap` is not: it beats
   the rule above and squeezed the two columns to 2.4px apart, which is the
   original "ProgramState of Texas Emergency Assistance Registry" jam wearing
   a different hat. Honour what the author asked for — one column — instead of
   fighting the inline gap with !important. The tight gap is then a ROW gap
   between a label and the value beneath it, which is what they wanted. */
.block-html .info-row[style*="flex-direction:column"],
.block-html .info-row[style*="flex-direction: column"] {
  grid-template-columns: minmax(0, 1fr);
}

/* The same jam, three more markup shapes: the County Clerk staff directory,
   the Tax Office form list, and the HR document list. */
.block-html .staff-list { list-style: none; margin: 0; padding: 0; }
.block-html .staff-list li {
  display: grid;
  grid-template-columns: minmax(0, min(13rem, 40%)) minmax(0, 1fr);   /* see the container note above */
  gap: var(--space-1) var(--space-4);
  align-items: baseline;
  padding-block: var(--space-2);
  border-top: 1px solid var(--color-border);
}
.block-html .staff-list li:first-child { border-top: 0; }
.block-html .staff-role { font-weight: var(--fw-semibold); color: var(--cc-gray-700); } /* 10.0:1 ✓ */
.block-html .staff-division + .staff-division { margin-top: var(--space-5); }
.block-html .staff-division h4 { font-size: var(--fs-1); margin-bottom: var(--space-2); }
@media (max-width: 480px) {
  .block-html .staff-list li { grid-template-columns: minmax(0, 1fr); }
}

/* Guard 2 of the container fix described under `.info-value` above. It sits
   HERE, after both row definitions, on purpose: `@container` adds no
   specificity of its own, so a stacking rule placed before
   `.block-html .staff-list li` (0,2,1) would tie with it and lose on source
   order — which is exactly what happened on /government/county-clerk in the
   first cut of this fix, and the re-sweep caught it. */
@container (max-width: 26rem) {
  .block-html :is(.info-row, .staff-list li) { grid-template-columns: minmax(0, 1fr); }
  .block-html :is(.info-label, .staff-role) {
    font-size: var(--fs-meta);
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }
}

.block-html .form-download-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
}
.block-html .form-download-row:first-child { border-top: 0; }
.block-html .form-download-row > div { min-width: 0; }
.block-html .form-name { font-weight: var(--fw-semibold); color: var(--cc-navy); }
.block-html .form-desc { color: var(--cc-gray-700); }   /* 10.0:1 ✓ */

.block-html a.hr-doc, .block-html a.sd-form-tile {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: baseline;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: var(--radius);
  background: var(--color-surface);
  text-decoration: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.block-html a.hr-doc:hover, .block-html a.sd-form-tile:hover {
  border-left-color: var(--cc-gold);
  box-shadow: var(--shadow-1);
}
/* `.info` and `.ft-info` are the wrappers holding the title and the one-line
   description; without a rule they were inline and the two glued together
   ("Pre-Meeting & Intake ApplicationStart here — required to…"). */
.block-html :is(.hr-doc, .sd-task) > .info,
.block-html .ft-info {
  display: grid;
  gap: var(--space-1);
  flex: 1 1 16rem;
  min-width: 0;
}
.block-html :is(.name, .ft-name), .block-html .sd-task strong {
  font-weight: var(--fw-semibold);
  color: var(--color-link);
  overflow-wrap: anywhere;
}
.block-html :is(.desc, .ft-desc), .block-html .sd-task .info > span {
  color: var(--cc-gray-700);              /* 10.0:1 ✓ */
}

/* ── 41.4 Document and resource lists ─────────────────────────────────────
   `pdf-link` is 233 uses on 22 pages: the vendor's document link. It stays a
   text link (it lives inside prose and must keep its underline, WCAG 1.4.1),
   but it becomes a full-width row so a list of them reads as a list. */
.block-html .resource-list, .block-html .prea-doc-list, .block-html .sd-wwd-list {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
}
.block-html :is(.resource-list, .prea-doc-list) li { padding-block: var(--space-1); }
.block-html .pdf-link {
  display: inline-block;
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}
.block-html .sd-wwd-list li {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
  padding-block: var(--space-1);
}
/* The vendor's icon spans lost their glyphs in migration and are now empty
   boxes that still reserve width. An empty decorative span shows nothing;
   hiding it removes the stray gap without inventing a replacement icon. */
.block-html :is(.ico, .division-icon, .nine11-icon, .icon, .cec-glance__overlay):empty { display: none; }
/* …except the What-We-Do list, where the marker carried the list semantics.
   A gold rule is a marker, not content. */
.block-html .sd-wwd-list li::before {
  content: "";
  flex: none;
  width: 0.5rem; height: 0.5rem;
  margin-top: 0.45em;
  border-radius: var(--radius-full);
  background: var(--cc-gold);
}

.block-html a.resource-link {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
  text-decoration: none;
}
.block-html a.resource-link:hover { background: var(--color-surface-tint); }
.block-html a.resource-link > div { display: grid; gap: var(--space-1); min-width: 0; }
.block-html a.resource-link strong { color: var(--color-link); }
.block-html a.resource-link small { font-size: var(--fs-0); color: var(--cc-gray-700); } /* 10.0:1 ✓ */
.block-html .resource-link-arrow { flex: none; color: var(--cc-gold-text); }             /* 6.3:1 ✓ */

/* ── 41.5 Buttons — 290 uses on 47 pages rendered as plain text links ──────
   Mapped onto the token-validated `.btn` variants rather than restyled ad
   hoc, so the contrast that was proven once stays proven. `.btn-warn-signup`
   is the WarnCentralTexas emergency-alert call to action and carries no
   `.btn` class at all, so it needs the base too. */
.block-html :is(.btn-primary, .btn-outline, .btn-gold, .btn-sm, .btn-lg),
.block-html a.btn-warn-signup {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  padding: var(--space-3) var(--space-5);
  min-height: 44px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--transition), box-shadow var(--transition);
}
.block-html :is(.btn-primary, .btn-outline, .btn-gold, .btn-sm, .btn-lg):hover,
.block-html a.btn-warn-signup:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.block-html .btn-primary, .block-html a.btn-warn-signup {
  background: var(--grad-navy-btn);
  color: var(--color-text-invert);        /* 8.1:1+ ✓ */
}
.block-html .btn-gold { background: var(--grad-gold-btn); color: var(--cc-navy-dark); }  /* 4.7:1+ ✓ */
.block-html .btn-outline {
  background: transparent;
  border-color: var(--cc-navy);
  color: var(--cc-navy);                  /* 11.6:1 ✓ */
}
.block-html .btn-outline:hover { background: var(--cc-navy); color: var(--color-text-invert); }
/* Size modifiers last so they win over the base padding above. */
.block-html .btn-sm { padding: var(--space-2) var(--space-4); min-height: 36px; }
.block-html .btn-lg { padding: var(--space-4) var(--space-7); font-size: var(--fs-1); min-height: 48px; }

/* ── 41.6 Legacy tables ───────────────────────────────────────────────────
   Three vendor table classes, one contract — the same one `.data-table` uses
   in §17. These are inside .block-html and carry no `.data-table` class, and
   the content may not be edited, so the contract is restated rather than
   shared. */
.block-html :is(.fee-table, .cp-table, .el-table) {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-0);
  margin-bottom: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
}
.block-html :is(.fee-table, .cp-table, .el-table) :is(th, td) {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
  vertical-align: top;
}
.block-html :is(.fee-table, .cp-table, .el-table) thead th {
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* 11.6:1 ✓ */
  font-weight: var(--fw-semibold);
  border-top: 0;
}
.block-html :is(.fee-table, .cp-table, .el-table) tbody th {
  font-weight: var(--fw-semibold);
  color: var(--color-text);
}
.block-html :is(.fee-table, .cp-table, .el-table) tbody tr:nth-child(even) :is(td, th) {
  background: var(--color-surface-tint);
}
.block-html :is(.fee-table, .cp-table, .el-table) caption {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-weight: var(--fw-bold);
  color: var(--cc-navy);
  font-family: var(--font-display);
}
/* A three-column officeholder table is 469px of content in a 375px viewport.
   `.el-table-wrap` is the vendor's scroll container and had no rules, so the
   table simply overflowed. */
.block-html .el-table-wrap {
  overflow-x: auto;
  contain: content;
  -webkit-overflow-scrolling: touch;
  margin-bottom: var(--space-5);
}

/* ── 41.7 Legacy disclosure (Burn Ban FAQ) ────────────────────────────────
   Same double-marker defect as the collection-list accordion: the browser's
   own ▶ plus the vendor's drawn ▾, pointing different ways. */
.block-html .faq-item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  box-shadow: var(--shadow-1);
}
.block-html .faq-item + .faq-item { margin-top: var(--space-3); }
.block-html .faq-question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  list-style: none;
  cursor: pointer;
  padding: var(--space-4) var(--space-5);
  min-height: 48px;
  font-weight: var(--fw-semibold);
  color: var(--cc-navy);                  /* 11.6:1 ✓ */
}
.block-html .faq-question::-webkit-details-marker { display: none; }
.block-html .faq-question::marker { content: ""; }
.block-html .faq-question:hover { background: var(--color-surface-tint); }
.block-html .faq-chevron { flex: none; color: var(--cc-gold-text); transition: transform var(--transition); }
.block-html .faq-item[open] > .faq-question { border-bottom: 1px solid var(--color-border); }
.block-html .faq-item[open] > .faq-question .faq-chevron { transform: rotate(180deg); }
.block-html .faq-answer { padding: var(--space-4) var(--space-5); }

/* ── 41.8 Sanitation task router (`sd-*`) ─────────────────────────────────
   "What do you need to do?" is the entry point for every county permit and it
   rendered as one wrapped paragraph of six titles glued to six descriptions
   (V-08). Below it, "1Call to schedule" / "2Download the form". */
.block-html a.sd-task {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-top: 3px solid var(--cc-gold);
  border-radius: var(--radius);
  background: var(--color-surface);
  box-shadow: var(--shadow-1);
  text-decoration: none;
  height: 100%;
  transition: transform var(--transition), box-shadow var(--transition);
}
.block-html a.sd-task:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.block-html .sd-form-group + .sd-form-group { margin-top: var(--space-5); }
.block-html .sd-form-group > h3 { font-size: var(--fs-2); margin-bottom: var(--space-3); }
.block-html .sd-step {
  padding: var(--space-4);
  background: var(--color-surface-tint);
  border-radius: var(--radius);
  border-left: 3px solid var(--cc-navy-mid);
}
.block-html .sd-step > strong {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
  color: var(--cc-navy);                  /* 11.6:1 ✓ */
  font-size: var(--fs-1);
}
.block-html .sd-step p { margin: 0; }
/* The step number was glued to the step title. It is a numbered disc. */
.block-html .sd-step .n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2rem; height: 2rem;
  border-radius: var(--radius-full);
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* 11.6:1 ✓ */
  font-family: var(--font-ui);
  font-weight: var(--fw-heavy);
}

/* ── 41.9 Crime-prevention pages (`cp-*`) ─────────────────────────────────
   Six long-form Sheriff's Office guides written as sections with a table of
   contents, checklists and callouts. */
.block-html .cp-section + .cp-section { margin-top: var(--space-7); }
.block-html .cp-section > h2 {
  font-size: var(--fs-4);
  padding-bottom: var(--space-3);
  border-bottom: 2px solid var(--cc-gold);
}
.block-html .cp-toc {
  background: var(--color-surface-tint);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
  box-shadow: none;
  margin-bottom: var(--space-6);
}
.block-html .cp-toc h2 { font-size: var(--fs-2); margin-bottom: var(--space-3); }
.block-html .cp-toc ol { margin: 0; padding-left: 1.4em; }
.block-html .cp-toc li { margin-bottom: var(--space-1); }
.block-html .cp-checklist { list-style: none; margin: 0 0 var(--space-5); padding: 0; }
.block-html .cp-checklist li {
  position: relative;
  padding-left: var(--space-6);
  margin-bottom: var(--space-3);
}
.block-html .cp-checklist li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.5em;
  width: 0.75rem; height: 0.75rem;
  border-radius: var(--radius-sm);
  background: var(--cc-navy-mid);
}
.block-html .cp-checklist.dontdo li::before { background: var(--cc-red); }
.block-html .cp-callout {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  margin: var(--space-5) 0;
  background: var(--alert-info-bg);
  color: var(--alert-info-fg);            /* 10.1:1 ✓ */
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.block-html .cp-callout a { color: inherit; }
.block-html .cp-callout.danger {
  background: var(--cc-red-light);
  color: var(--cc-red);                   /* 6.0:1 ✓ */
  border-left-color: var(--cc-red);
}
.block-html .cp-callout.success {
  background: var(--cc-green-light);
  color: var(--cc-green);                 /* 6.9:1 ✓ */
  border-left-color: var(--cc-green);
}
.block-html .cp-contact-card {
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* 11.6:1 ✓ */
  border-radius: var(--radius);
  padding: var(--space-6);
  margin-top: var(--space-6);
}
.block-html .cp-contact-card :is(h2, h3, p) { color: inherit; }
.block-html .cp-contact-card a { color: var(--color-link-invert); }   /* gold on navy 5.6:1 ✓ */
.block-html .cp-contact-card .num {
  font-family: var(--font-ui);
  font-size: var(--fs-3);
  font-weight: var(--fw-heavy);
  color: var(--cc-gold-bright);           /* on navy 5.6:1 ✓ */
}

/* ── 41.10 The orphan elections design system (`el-*`) ────────────────────
   Twelve class names used by exactly one page, elections `/candidates`. The
   right fix is to re-author it with the site's real blocks (FULL-REVIEW P1),
   which is content work; until then it must at least be readable. */
.block-html .el-hero-inner { padding-block: var(--space-5); }
.block-html .el-hero-eyebrow {
  font-size: var(--fs-meta);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cc-gold-text);             /* 6.3:1 ✓ */
  margin-bottom: var(--space-2);
}
.block-html .el-hero-date { font-size: var(--fs-1); color: var(--color-text); }
.block-html .el-hero-note { color: var(--cc-gray-700); }   /* 10.0:1 ✓ */
.block-html .el-grid-2 {
  display: grid;
  gap: var(--space-4);
  align-items: start;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 768px) { .block-html .el-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.block-html .el-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-top: 3px solid var(--cc-gold);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-5);
  min-width: 0;
}
.block-html .el-card > :first-child { margin-top: 0; }
.block-html .el-card > :last-child { margin-bottom: 0; }
.block-html .el-card h3 { font-size: var(--fs-2); }
.block-html .el-docs { list-style: none; margin: 0; padding: 0; }
.block-html .el-docs li { padding-block: var(--space-2); border-top: 1px solid var(--color-border); }
.block-html .el-docs li:first-child { border-top: 0; }
/* Source badges were glued to their link text:
   "Caldwell County Democratic PartyParty", "Poll Watchers GuidePDF". */
.block-html .el-doc-type {
  display: inline-flex;
  align-items: center;
  margin-left: var(--space-2);
  padding: 0 var(--space-2);
  min-height: 22px;
  border-radius: var(--radius-full);
  border: 1px solid currentColor;
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-decoration: none;
  color: var(--cc-gold-text);             /* 6.3:1 ✓ */
  background: var(--cc-gold-light);       /* 5.3:1 ✓ */
  vertical-align: middle;
}
.block-html .el-contact { margin: 0; display: grid; gap: var(--space-2); }
.block-html .el-contact > div {
  display: grid;
  grid-template-columns: minmax(6rem, 8rem) minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  align-items: baseline;
}
.block-html .el-contact dt { font-weight: var(--fw-semibold); color: var(--cc-gray-700); } /* 10.0:1 ✓ */
.block-html .el-contact dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 480px) {
  .block-html .el-contact > div { grid-template-columns: minmax(0, 1fr); }
}
/* `el-stack` is the vendor's phone treatment: the row header stays, each cell
   is labelled from its own `data-label`. */
@media not all and (min-width: 768px) {
  .block-html .el-table.el-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .block-html .el-table.el-stack tr { display: block; border-top: 1px solid var(--color-border); padding-block: var(--space-2); }
  .block-html .el-table.el-stack :is(td, th) { display: block; border: 0; padding-block: var(--space-1); }
  .block-html .el-table.el-stack td[data-label]::before {
    content: attr(data-label) ": ";
    font-weight: var(--fw-semibold);
    color: var(--cc-gray-700);            /* 10.0:1 ✓ */
  }
  .block-html .el-table.el-stack tbody tr:nth-child(even) :is(td, th) { background: none; }
}

/* ── 41.11 Human Resources (`hr-*`) ───────────────────────────────────────*/
.block-html .hr-eoe {
  background: var(--cc-navy-light);
  color: var(--cc-navy);                  /* 10.1:1 ✓ */
  border: 0;
  border-left: 4px solid var(--cc-navy-mid);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-bottom: var(--space-5);
}
.block-html .hr-section-title { font-size: var(--fs-3); margin-top: 0; }
.block-html a.hr-year {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}
.block-html a.hr-year:hover { border-color: var(--cc-gold); box-shadow: var(--shadow-1); }
.block-html a.hr-year.current { border-color: var(--cc-navy); background: var(--cc-navy-light); }
.block-html .hr-year .badge { color: var(--cc-gold-text); background: var(--cc-gold-light); } /* 5.3:1 ✓ */

/* ── 41.12 Stat tiles and feature tiles ──────────────────────────────────
   The Sheriff's band printed as eight bare lines: 24/7 / Jail Operations /
   4 / County Precincts Served / … (V-10). */
.block-html .stats-row, .block-html .feature-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: var(--space-5);
}
@media (min-width: 768px) {
  .block-html .stats-row { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
.block-html :is(.stat-tile, .feature-tile) {
  text-align: center;
  background: var(--color-surface-brand);
  border: 0;
  box-shadow: none;
}
.block-html :is(.stat-tile .num, .ft-num) {
  display: block;
  font-family: var(--font-ui);
  font-weight: var(--fw-heavy);
  font-size: var(--fs-4);
  line-height: var(--lh-tight);
  color: var(--cc-navy);                  /* 10.1:1 on navy-light ✓ */
}
.block-html :is(.lbl, .ft-label) {
  display: block;
  margin-top: var(--space-1);
  color: var(--cc-gray-700);              /* 10.0:1 ✓ */
  font-weight: var(--fw-semibold);
}
.block-html .kit-item {
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-tint);
  border-radius: var(--radius);
  border-left: 3px solid var(--cc-gold);
}
.block-html .count { display: inline-flex; align-items: center; white-space: nowrap; }

/* ── 41.13 Emergency and alert panels ────────────────────────────────────
   "Life-threatening emergency? Call 911 immediately." rendered as an ordinary
   bold paragraph while the (fabricated) Weather Advisory above it was a fully
   styled banner — the invented alert carried more visual weight than the real
   emergency instruction (V-11). It gets the urgent alert pairing. */
.block-html .emergency-911 {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
  background: var(--alert-urgent-bg);
  color: var(--alert-urgent-fg);          /* white on red 6.5:1 ✓ */
  border-radius: var(--radius);
}
.block-html .emergency-911 strong { display: block; font-size: var(--fs-1); }
.block-html .emergency-911 a { color: inherit; }
.block-html .alert-banner {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-4) var(--space-5);
  background: var(--alert-warning-bg);
  color: var(--alert-warning-fg);         /* 13.1:1 ✓ */
  border-left: 4px solid var(--alert-warning-accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-bottom: var(--space-5);
}
.block-html .callout-important {
  padding: var(--space-4) var(--space-5);
  background: var(--alert-warning-bg);
  color: var(--alert-warning-fg);         /* 13.1:1 ✓ */
  border-left: 4px solid var(--alert-warning-accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-bottom: var(--space-5);
}
.block-html .callout-title {
  font-family: var(--font-ui);
  font-weight: var(--fw-bold);
  font-size: var(--fs-2);
  margin-bottom: var(--space-2);
}
.block-html .callout-important > :last-child { margin-bottom: 0; }
.block-html .warn-hero {
  display: grid;
  gap: var(--space-5);
  align-items: center;
  background: var(--cc-navy);
  color: var(--color-text-invert);        /* 11.6:1 ✓ */
  border-radius: var(--radius);
  padding: var(--space-6);
  margin-bottom: var(--space-5);
}
@media (min-width: 768px) { .block-html .warn-hero { grid-template-columns: minmax(0, 1fr) 18rem; } }
.block-html .warn-hero :is(h2, h3, p, li) { color: inherit; }
.block-html .warn-hero ul { margin: 0; padding-left: 1.3em; }
.block-html .warn-cta { text-align: center; }
.block-html .warn-note { margin: var(--space-3) 0 0; color: inherit; font-size: var(--fs-0); }
.block-html .pull-quote {
  border-left: 4px solid var(--cc-navy-mid);
  padding: var(--space-3) var(--space-5);
  background: var(--color-surface-tint);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-family: var(--font-display);
  font-style: italic;
  color: var(--cc-gray-700);              /* 10.0:1 ✓ */
}
.block-html .pull-quote cite { display: block; margin-top: var(--space-2); font-style: normal; font-size: var(--fs-0); }
.block-html .cec-glance__video { display: block; width: 100%; border-radius: var(--radius); }
.block-html .court-schedule > h3 { margin-top: 0; }

/* ── 41.14 The 1rem body-text floor (SPEC §3.2) ──────────────────────────
   The migrated markup hard-codes inline `font-size` values between .75rem and
   .95rem on ordinary body copy — measured down to 13.12px, 30 such elements
   on /departments/emergency-management alone (V-18). An inline declaration
   can only be beaten by !important.

   The selector is exact, not a guess: it matches an inline font-size whose
   value STARTS WITH A DECIMAL POINT, i.e. is by definition below 1rem/1em.
   `font-size:1.05rem` and `font-size:2.5rem` do not match and are untouched.
   Both spellings the migrated markup uses (with and without a space after the
   colon) are covered. Kickers and badges are unaffected: they are class-styled
   with --fs-meta, not inline-styled. */
.block-html [style*="font-size:."],
.block-html [style*="font-size: ."] { font-size: var(--fs-0) !important; }

/* ── 42. Unclaimed property — routes/unclaimed.js ──────────────────────────
   Three public pages: the list, one record with its claim form, and the
   claimant's own status page.

   THIS SECTION OWNS ALMOST NOTHING. Layout comes from `.container`, panels from
   `.callout` and `.card`, the table from `.data-table` inside `.table-scroll`,
   every form control from §24, the empty state from `.empty-note`, paging from
   `.pagination`, and headings from `.section-head.has-rule`. What is left here
   is the handful of things genuinely particular to this page: the money column,
   the phone card flip, the radio list, the one-of-two pairing, and the
   honeypot.

   The previous version of this section reinvented all of the above and got the
   details wrong — it rendered callouts as two side-by-side columns, the claim
   button as invisible chrome, and every page flush to the edge of the window.
   If something here starts to look like a general-purpose component, it belongs
   further up this file instead. */

/* Chris finds minimum-AA small text washed out, so the module re-points the
   muted alias to the 10.0:1 grey for its own subtree. Scoped to the container
   div and NEVER to <body>: on <body> it would reach the shared header, nav and
   footer and change pixels on components validated elsewhere. */
.uc-page { --color-text-muted: var(--cc-gray-700); }

/* Anchor targets must clear the sticky header, which measures 152px pinned at
   every width from 320 to 1280. 6rem (96px) left every jump 56px short, so a
   linked field in the error summary landed UNDER the header. */
.uc-page [id] { scroll-margin-top: 10.5rem; }

/* ── layout, rhythm and measure ────────────────────────────────────────────
   READ THIS BEFORE ADDING A `>` SELECTOR HERE. `page()` now puts `.uc-main`
   (and, when the page has one, `.uc-aside`) between `.uc-page` and the page
   body. Every rule below used to be rooted at `.uc-page > …`; against the new
   markup each of those matched exactly ONE element — the layout div — and the
   whole vertical rhythm of all three pages went to zero without a single
   selector failing to parse. Anything written with a child combinator must be
   rooted at `.uc-main` or `.uc-aside`, never at `.uc-page`. Descendant
   selectors were never affected and stay where they were. */
.uc-main  { min-width: 0; }
.uc-aside { min-width: 0; }
.uc-main  > * + *             { margin-top: var(--space-6); }
.uc-main  > section + section { margin-top: var(--space-10); }
.uc-aside > * + *             { margin-top: var(--space-5); }
.uc-page section > * + *      { margin-top: var(--space-5); }
.uc-page fieldset + fieldset  { margin-top: var(--space-7); }
/* `.uc-page section > .table-scroll { margin-top: var(--space-4) }` is DELETED,
   not moved. It never fired: `.section-head` carried margin-bottom
   var(--space-5) and adjacent-sibling margins collapse to the LARGER value, so
   the results table measured 23px from the heading that counts it, not the 16px
   the rule asked for — a rule that keeps looking correct in review while doing
   nothing. The job is now done at the source, below. */

/* A HEADING BINDS DOWNWARD — the thing the block above claims to do and only
   ever did between sections. Section 1 gives every h2 `margin: 0 0
   var(--space-4)` and the section rhythm gives the next block var(--space-5);
   the two collapse to 24px, the same as block-to-block, so a heading hung
   exactly as far from what it labelled as from what came before it. Zero the
   heading's own margin FIRST — then the collapse has nothing left to win with —
   and set the gap from the content side. Result: 12px heading-to-content, 24px
   content-to-content, 64px section-to-section. */
.uc-page section > h2     { margin-bottom: 0; }
.uc-page section > h2 + * { margin-top: var(--space-3); }

/* Every h2 on these pages drops one rank EXCEPT the one that answers the
   resident's question, which keeps the site's default h2 size and therefore
   needs no rule at all. Before this, "1 item on the county's list" (432px) was
   typographically identical to "About this list" (240px) and "Search the list"
   (242px) — same --fs-4, same navy, same 56px gold tick — so nothing on the
   page distinguished the answer from the furniture. After it, `.has-rule` means
   exactly one thing site-wide: a subordinate section label. */
.uc-main h2.has-rule { font-size: var(--fs-3); }

/* ONE measure, and it is applied to TEXT INSIDE A BOX, never to the box.
   This section previously invented 46rem, 42rem, 36rem, 32rem and 28rem — five
   right edges, not one of them a token, nothing on the page sharing one, and up
   to 720px of the 1232 permanently blank. --content-width (60rem) is the site's
   declared prose measure but yields 83 characters per line at 16px, which IS
   the fee-cap paragraph defect; the no-results line measured 113. 34rem is
   544px, about 68 characters at 16px Inter and about 60 at the 18px lede —
   inside the 45-75 band at both sizes.
   Every prose block on these pages now sits in a card, a callout or the
   empty-state card, so the BORDER supplies the right edge the eye actually
   reads and the cap is invisible padding. That is how the page gets one visible
   edge per column and still never runs a line past 68 characters. */
.uc-page { --uc-measure: 34rem; }
.uc-main > .prose,
.uc-main > section > .prose,
.uc-main .card > .prose,
.uc-main .empty-note > .prose { max-width: var(--uc-measure); }

/* THE ONE SELECTOR ON THESE PAGES THAT HAS TO WIN A FIGHT. Section 15 sets
   `.callout__body > .prose { max-width: none }` at (0,2,0) so a callout fills
   its own box; in a 784px main column that is 87 characters per line for the
   Texas Property Code 76.506 paragraph and for every error summary. This is
   (0,3,0) and beats it.
   DO NOT shorten this to `.uc-page .prose`. That is (0,2,0), TIES with section
   15, and — being later in the file — would win everywhere and squeeze the body
   of every callout on the page down to 544px including its padding. The comment
   this replaces recorded the same trap. */
.uc-main .callout__body > .prose { max-width: var(--uc-measure); }

/* THE RAIL, AND WHY IT IS 26rem AND NOT THE 20rem /foreclosures USES.
   416px means a `.callout` inside it reads across
     416 - 24 - 24 (padding) - 4 (left bar) - 24 (icon) - 12 (gap) = 328px,
   about 41 characters at 16px — a newspaper column. At 20rem the same
   paragraph reads at 232px, about 29 characters, which is too narrow for the
   one piece of legally protective text on the page. 26rem is also what sets the
   main column: 1232 - 416 - 32 = 784px at 1280, and 976 - 416 - 32 = 528px at
   1024, which is why the register's card breakpoint moves to 1280 below.
   DELIBERATELY NOT STICKY. On the record page this rail carries the fee-cap
   callout, "What happens", the offline route and the contact card — 700-900px
   against a 900px window with 152px already spent on the pinned header. Sticky
   would park its lower half permanently out of reach, which is V-04, the exact
   defect section 37's own comment records fixing on /foreclosures. */
.uc-layout { --rail: 26rem; }
.uc-aside .card h2 { font-size: var(--fs-2); }

/* NONE of the cards on these pages is clickable. Section 13's `.card:hover`
   lifts the box 2px, swaps to --shadow-3 and turns the border gold — right for
   a tile, wrong for the county's statement of what it owes somebody, which
   twitched under the cursor. `.fc-list .doc-link:hover { transform: none }` is
   the house precedent for suppressing it.
   The second line exists because `border-color` in the first resets all four
   edges, including the record card's gold top rule. */
.uc-page .card:hover {
  transform: none;
  box-shadow: var(--shadow-1);
  border-color: var(--color-border);
}
.uc-page .card.uc-record:hover { border-top-color: var(--cc-gold); }

/* ── search ────────────────────────────────────────────────────────────────
   Replaces `class="filter-rail uc-search"` — section 26's 260px rail of the
   two-column `.filter-layout` grid (built for /jobs) rendered standalone as a
   576x370px tinted slab, 7.9x the height of the house search row on
   /foreclosures. That height is the whole reason the only control on the page
   sat 1,382px down a phone.
   Named areas rather than flex order, so DOM order, visual order and focus
   order agree at both widths and nothing is reordered by CSS (WCAG 1.3.2). */
.uc-search {
  display: grid;
  gap: var(--space-3) var(--space-4);
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "q q" "city go";
  align-items: end;
}
.uc-search__q    { grid-area: q; }
.uc-search__city { grid-area: city; }
.uc-search__go   { grid-area: go; }
/* Section 24's `.field` carries margin-bottom var(--space-5) and max-width
   32rem, both of which fight a grid row. `min-width: 0` is section 26's
   documented guard: without it the longest town name sets the column's
   min-content and pushes the page into horizontal scroll at 320px
   (WCAG 1.4.10). */
.uc-search .field { margin-bottom: 0; max-width: none; min-width: 0; }
.uc-search select { width: 100%; max-width: 100%; }
.uc-search .btn   { width: 100%; }
.uc-clear { margin: 0; }
@media (min-width: 480px) {
  .uc-search {
    grid-template-columns: minmax(0, 1fr) 12rem auto;
    grid-template-areas: "q city go";
  }
  .uc-search .btn { width: auto; }
}

/* The no-results card is not an empty state — it carries three real next
   actions, so it is a `.card` and not `.empty-note`. */
.uc-next { list-style: none; margin: 0; padding: 0; }
.uc-next li + li { margin-top: var(--space-3); }

/* ── the register ──────────────────────────────────────────────────────────
   Four columns and the money is column two. It used to be column four of five,
   at 16px/400 in the narrowest track, 1,043px of eye travel from the surname
   that matched. Column five was 25 identical navy "This is mine" buttons —
   which meant the page had no primary action at all, and forced a resident to
   assert ownership in order to READ a record. The surname is the link now, and
   its accessible name is a name rather than 25 repetitions of one phrase. */
.uc-table { table-layout: fixed; }
/* Amount is sized for the widest figure the register can legitimately hold, not
   for the typical one. `$1,234,567.89` in 21px bold tabular figures measures
   170px, and `.uc-num` is nowrap, so at the 20% the arithmetic first suggested
   (156px of content) it overflowed its cell rather than wrapping. The
   $100 Comptroller figure in the other app is a REPORTING threshold, not a cap
   on what the county may be holding, so there is no ceiling to design to.
   26% is 204px, giving the figure 172px of content. The description gives up
   the width, because it is the one column on this page allowed to wrap. */
.uc-col-name   { width: 30%; }
.uc-col-amount { width: 26%; }
.uc-col-what   { width: 26%; }
.uc-col-city   { width: 18%; }
/* Section 17 pads cells var(--space-3) var(--space-5) — 48px of gutter per
   cell. At a 784px main column that leaves the amount 109px, and
   `$1,234,567.89` in tabular figures is about 110px while `.uc-num` is nowrap,
   so it would overflow rather than wrap. 32px of gutter gives it 125px. */
.uc-table th, .uc-table td { padding-inline: var(--space-4); overflow-wrap: anywhere; }

/* Money gets rank: size, weight and the darkest ink in the palette. NOT gold.
   --cc-gold is 2.70:1 on white and --cc-gold-text 6.3:1, against 15.4:1 from
   --cc-navy-dark; on a page written for elderly readers the mark for a number
   is size, weight and a shared decimal point, not the county's palest hue.
   Written as `.uc-table .uc-num` (0,2,0) on purpose: a bare `.uc-num` is
   (0,1,0) and LOSES to `.data-table td` (0,1,1), so the column silently stayed
   left-aligned — the bug the comment this replaces recorded. */
.uc-table .uc-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* CELLS ONLY. `.uc-table .uc-num` also matches the COLUMN HEADER, and section
   17 paints `thead th` white on --cc-navy-mid; setting --cc-navy-dark there put
   navy-dark on navy-mid — 1.3:1, an invisible header — while every other header
   stayed white. Rank belongs to the figure, not to the word "Amount". */
.uc-table td.uc-num {
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  color: var(--cc-navy-dark);            /* 15.4:1 on white */
}
.uc-sub { display: block; font-size: var(--fs-meta); color: var(--color-text-muted); }
/* Size as well as family. Setting only the family meant this class rendered at
   16px in a <dd> and at 34px faux-bold inside an <h2> — ui-monospace ships no
   900 weight, so the browser synthesised one, and the page that reports a
   decision carried three type systems in one heading. */
.uc-ref { font-family: var(--font-mono); font-size: var(--fs-0); white-space: nowrap; }

/* THE NAME COLUMN STOPS CHECKERBOARDING. Section 17 tints `tbody th` on every
   row and `tr:nth-child(even) td` on alternate ones, so at desktop the surname
   cell was tinted against four white cells on odd rows and disappeared into the
   stripe on even ones. Contrast was fine either way (15.41:1); rhythm was the
   failure, on the one column the whole page exists to be scanned. `.doc-table`
   (section 36) already solved this; these are the same two rules. */
.uc-table tbody th[scope="row"] { background: transparent; }
.uc-table tbody tr:nth-child(even) th[scope="row"] { background: var(--color-surface-tint); }
/* Underlined: colour is never the only cue on this page, and as far as a reader
   is concerned this sits inside a block of text. */
.uc-table tbody th[scope="row"] a {
  font-weight: var(--fw-semibold);
  text-decoration: underline;
}

/* Anything below 1280: every row becomes its own card.
   The switch used to be 1024, on the reasoning that five columns need the full
   1024px. Main is no longer the page: with a 26rem rail beside it, 1024 leaves
   main 528px and only 1280 gives it 784. So the ONE number in this query moves
   1024 -> 1280 and nothing else moves with it. Written
   `not all and (min-width: 1280px)` rather than `max-width: 1279px` because
   this file declares exactly four breakpoints and 1279 would be a fifth. */
@media not all and (min-width: 1280px) {
  /* Otherwise a bordered, shadowed box frames a stack of bordered boxes.
     `contain` is released ONLY here; above this width it is the Chromium
     overflow-leak guard documented at section 21. */
  .uc-page .table-scroll {
    border: 0; border-radius: 0; box-shadow: none; background: none;
    overflow: visible; contain: none;
  }
  /* Clipped, NOT display:none — display:none drops the header cells out of the
     accessibility tree and breaks the association the labels depend on. */
  .uc-table thead {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  .uc-table, .uc-table tbody, .uc-table th, .uc-table td { display: block; }
  /* A two-column grid, not a stack. Label-above-value put the amount under its
     own caption and made every card 350px tall — two results a phone screen.
     Surname left, figure right on line one is about 155px, which is five. */
  .uc-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-1) var(--space-4);
    align-items: baseline;
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--cc-navy-mid);
    border-radius: var(--radius);
    box-shadow: var(--shadow-1);
    background: var(--color-surface);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
  }
  .uc-table tbody th[scope="row"] {
    grid-column: 1; grid-row: 1;
    font-size: var(--fs-2);
    font-weight: var(--fw-bold);
    color: var(--cc-navy);
  }
  .uc-table .uc-num { grid-column: 2; grid-row: 1; text-align: right; }
  .uc-table td:not(.uc-num) { grid-column: 1 / -1; }
  /* Zebra striping and row hover off. A tap painted a whole card navy and stuck
     on iOS. The house rules paint the CELLS, so overriding the row does
     nothing; these match cell-for-cell. `tr:nth-child(even) th[scope="row"]` is
     NEW to this list and is required now that the register stripes column 1
     above the breakpoint — without it the card's name cell inherits the desktop
     stripe. */
  .uc-table tbody th,
  .uc-table tbody tr:nth-child(even) th[scope="row"],
  .uc-table tbody tr:nth-child(even) td,
  .uc-table tbody tr:hover td,
  .uc-table tbody tr:hover th { background: var(--color-surface); }
  .uc-table td, .uc-table th { border: 0; padding: 0; text-align: left; }
  .uc-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--fs-meta);
    font-weight: var(--fw-semibold);
    color: var(--color-text-muted);
  }
  .uc-table .uc-num { font-size: var(--fs-2); }
}
@media not all and (min-width: 480px) {
  /* At 343px the figure and a long surname cannot share a line. */
  .uc-table tr { grid-template-columns: minmax(0, 1fr); }
  .uc-table .uc-num { grid-column: 1; grid-row: auto; text-align: left; }
}

/* Everything on these pages is flush left; the page numbers were the one thing
   that jumped to the horizontal centre, and then "Page 2 of 9" landed back at
   x=24 beneath them. */
.uc-page .pagination { justify-content: flex-start; }
/* `.pagination a` is inline-flex with min-height 44px so the <li>s stretch;
   `.uc-gap` is a 26.4px inline-block on the first line box and sat about 9px
   above the numbers it separates. */
.uc-page .pagination li { display: flex; align-items: center; }
.uc-gap { display: inline-block; padding: 0 var(--space-2); color: var(--color-text-muted); }
.uc-pagenote { font-size: var(--fs-meta); color: var(--color-text-muted); }

/* ── the county's record ───────────────────────────────────────────────────
   The authoritative object on the page had no container at all: a bare <dl> of
   hairline rules floating between a 960px tinted warning callout and a 960px
   tinted info callout, so it read as loose text and looked LESS official than
   the disclaimer above it. /foreclosures wraps every equivalent block in
   `<section class="card fc-card">`; this is that, plus the 3px gold top rule
   `.doc-folder-card .card--link` (section 36) already uses to mean "a county
   object of record".
   GOLD'S WHOLE JOB on these pages is that rule and the notice edges. It never
   marks the money — --cc-gold is 2.70:1 on white and --cc-gold-text 6.3:1,
   against 15.4:1 available from --cc-navy-dark — and it never marks an
   action. */
.uc-record { border-top: 3px solid var(--cc-gold); }
.uc-record > * + * { margin-top: var(--space-4); }
.uc-record__amount {
  font-family: var(--font-display);
  font-size: var(--fs-4);
  font-weight: var(--fw-black);
  line-height: var(--lh-tight);
  color: var(--cc-navy-dark);            /* 15.4:1 on white */
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.uc-record__meta { margin: 0; color: var(--cc-gray-700); }   /* 10.0:1 */
.uc-record__act  { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 0; }
@media not all and (min-width: 480px) {
  .uc-record__act { display: block; }
  .uc-record__act .btn { width: 100%; }
  .uc-record__act .btn + .btn { margin-top: var(--space-3); }
}

/* The form sits in a card at the column edge, so the card's border is the edge
   the eye reads and section 24's fieldset border would be a box drawn inside a
   box — three nested rectangles once the capacity radios are on screen. Only
   the TOP-LEVEL steps lose their border; a nested fieldset keeps section 24's,
   because that group has to read as a group. The child combinators are
   load-bearing: a descendant selector would strip the nested one too. */
.uc-claim > form > fieldset { border: 0; padding: 0; }
.uc-claim > form > fieldset > legend { padding-inline: 0; }

/* ONE RANK IS ADDED TO THE FORM, and it is the label. The hints total 712px of
   height against 757px for every control combined, because hint, label and the
   typed value are all 16px with only weight and a grey between them — nothing
   can be skimmed. Shrinking the hint is not available: body/UI text on this
   site never drops below 1rem and --fs-meta is label typography. Raising the
   label gives three ranks with nothing below 1rem:
     18/600 --cc-navy-dark (15.4:1) -> 16/400 --cc-gray-700 (10.0:1) -> 16/400
     --cc-gray-900 in the control (15.4:1). */
.uc-form .field label { font-size: var(--fs-1); }
/* City/State/ZIP shared a line but not a right edge with the fields above them:
   `.uc-row .field` sets max-width:none, so the row ran to the card while every
   other field stopped at 32rem. */
.uc-form .uc-row { max-width: 32rem; }
/* Back and Send share one row, so the ladder of controls ends on the primary
   one. DOM order is unchanged (nav, then submit), so focus order is unaffected. */
.uc-wiz__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); }
.uc-wiz__foot > * { margin: 0; }
.uc-submit { margin: 0; }
.uc-submit .field__hint { margin: 0 0 var(--space-3); }

/* ── record facts / claim facts ─────────────────────────────────────────── */
/* `.contact-row` is a flex row built for the narrow contact card in §20, where
   a label sits beside an icon. Reused at this width it cannot form a column, so
   every value started at a different x and the block read as ragged text. Here
   it becomes a real two-column definition grid. */
.uc-facts .contact-row {
  display: grid;
  grid-template-columns: minmax(8rem, 11rem) 1fr;
  gap: var(--space-3) var(--space-5);
  align-items: baseline;
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}
.uc-facts .contact-row:last-child { border-bottom: 0; padding-bottom: 0; }
.uc-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
@media not all and (min-width: 480px) {
  .uc-facts .contact-row { grid-template-columns: 1fr; gap: var(--space-1); }
}
.uc-steps { padding-left: var(--space-5); }
.uc-steps li + li { margin-top: var(--space-3); }

.uc-badge { margin-left: var(--space-3); vertical-align: middle; }

/* ── the claim form ─────────────────────────────────────────────────────── */
/* `.field` (§24) supplies label, hint, control, error and a 32rem measure.
   Nothing here restates any of that. */

/* The capacity radios. The fieldset+legend IS the group; this is only the
   layout. Each row is a full-width target — the label is clickable, so the hit
   area is the whole card, not the 16px dot. */
.uc-choices { list-style: none; margin: 0; padding: 0; }
.uc-choices li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3);
  align-items: start;
  min-height: 44px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}
.uc-choices li + li { margin-top: var(--space-3); }
.uc-choices input[type="radio"] { width: 1.25rem; height: 1.25rem; margin-top: 0.15rem; }
.uc-choices label { font-weight: var(--fw-regular); cursor: pointer; margin: 0; }
/* Progressive: the native dot is the real state cue, this only reinforces it. */
.uc-choices li:has(:checked) {
  border-color: var(--cc-navy-mid);
  background: var(--cc-navy-xlight);
}

/* Email/phone: one of the two is required, so the pairing is shown as well as
   wired up with a shared aria-describedby. */
/* Was a 4px --color-accent left bar, which made gold mean a fourth thing on
   this page. With `.uc-vow` deleted and this changed, the ledger reads: gold =
   a county notice edge or record chrome; navy = structure and action.
   Body text on --color-surface-tint measures 14.4:1. */
.uc-oneof {
  padding: var(--space-4);
  background: var(--color-surface-tint);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-top: var(--space-4);
}
.uc-oneof .field:last-child { margin-bottom: 0; }

/* ── the name, as three boxes and one question ─────────────────────────────
   First / middle initial / last are separate CONTROLS but a single QUESTION, so
   they sit in a fieldset whose legend asks it once. Section 24's fieldset border
   is dropped here for the same reason the step fieldsets drop theirs: the claim
   card already draws the edge, and a box inside a box inside a card is three
   rectangles for one question. */
.uc-name { border: 0; padding: 0; margin: 0; }
.uc-name > legend {
  padding-inline: 0;
  font-size: var(--fs-1);
  font-weight: var(--fw-semibold);
  color: var(--cc-navy-dark);            /* 15.4:1 on white */
}
/* NAMED AREAS, not flex. `.uc-row`'s flex needed 192 + 106 + 192 + 32 = 522px
   in a 512px card column, so the last-name box wrapped to its own line and the
   three boxes stopped reading as one name. A grid states the intent instead of
   negotiating it, and it is the same mechanism the search row uses.
   The initial gets one character's width and no more, so the row reads
   "a lot / a little / a lot" and it is obvious at a glance that one letter is
   what is wanted. On a phone the name takes the full width and the initial
   shares its line with the surname. */
.uc-name__row {
  display: grid;
  gap: var(--space-2) var(--space-4);
  grid-template-columns: 8rem minmax(0, 1fr);
  grid-template-areas: "first first" "mi last";
  /* The three labels are different heights — "Middle initial" wraps in a narrow
     column — so without this the three inputs sat at three different vertical
     positions and the row stopped reading as one name. Align the BOXES, not the
     tops of the labels. 8rem is what fits "Middle initial" on one line at the
     18px the form's labels now use. */
  align-items: end;
}
.uc-name__first { grid-area: first; }
.uc-name__mi    { grid-area: mi; }
.uc-name__last  { grid-area: last; }
.uc-name__row .field { margin-bottom: 0; max-width: none; min-width: 0; }
@media (min-width: 480px) {
  .uc-name__row {
    grid-template-columns: minmax(0, 1fr) 8rem minmax(0, 1fr);
    grid-template-areas: "first mi last";
  }
}

/* The checkbox and its label on one line, the box vertically centred against
   the first line of the label rather than sitting on the text baseline.
   min-height 44px is the house touch target (section 24). */
.uc-check {
  display: flex; align-items: center; gap: var(--space-3);
  margin: var(--space-3) 0 0; min-height: 44px;
}
.uc-check input { width: 1.25rem; height: 1.25rem; margin: 0; flex: none; }
.uc-check label { margin: 0; font-weight: var(--fw-regular); }

/* City / State / ZIP share a line on anything but a small phone. */
.uc-row { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.uc-row .field { margin-bottom: var(--space-4); max-width: none; }
.field--city  { flex: 2 1 12rem; }
.field--state { flex: 1 1 9rem; }
.field--zip   { flex: 1 1 8rem; }
.field--ssn input { max-width: 8rem; }
/* `not all and (min-width: 480px)` rather than `max-width: 479px`: this file
   declares exactly four breakpoints at the top, and 479 would be a fifth. */
@media not all and (min-width: 480px) { .uc-row { display: block; } }

/* `.uc-vow` is gone: it was a fourth hand-rolled copy of the notice strip.
   The repeat above the Send button is now `.note-strip.note-strip--warning`. */
.uc-submit { margin-top: var(--space-8); }

/* Off-screen, never display:none — a hidden-by-display field is skipped by some
   bots and by autofill, which is the opposite of what a honeypot needs. */
.uc-hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden;
}

/* ── documents and history ──────────────────────────────────────────────── */
.uc-docs { list-style: none; margin: 0; padding: 0; }
.uc-docs li {
  display: flex; flex-wrap: wrap; gap: var(--space-3);
  justify-content: space-between; align-items: baseline;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}
.uc-docs__name  { min-width: 0; overflow-wrap: anywhere; }
.uc-docs__state { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--color-text-muted); }

.uc-history { list-style: none; margin: 0; padding: 0; }
.uc-history li { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border); }
.uc-history__when {
  display: block; font-size: var(--fs-meta);
  font-weight: var(--fw-semibold); color: var(--color-text-muted);
}


/* The file input is absent from §24's base selector list, so on this page — the
   one place a member of the public uploads anything — it would otherwise be a
   raw browser widget below the 16px that stops iOS zooming on focus. Scoped
   here rather than added to §24, which would restyle /jobs' resume field too
   and needs its own visual pass. */
.uc-page input[type="file"] {
  width: 100%;
  font: inherit;
  font-size: max(16px, 1em);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-surface);
}
.uc-page input[type="file"]::file-selector-button {
  font: inherit;
  font-weight: var(--fw-semibold);
  min-height: 36px;
  padding: 0 var(--space-4);
  margin-right: var(--space-4);
  border: 2px solid var(--cc-navy);
  border-radius: var(--radius);
  background: transparent;
  color: var(--cc-navy);
  cursor: pointer;
}
.uc-page input[type="file"]::file-selector-button:hover {
  background: var(--cc-navy); color: var(--color-text-invert);
}

/* Nothing replaces the ::placeholder rule that stood here. src/util/form.js has
   no placeholder option by design, so this page has no placeholders to style;
   the rule was inert and its comment was actively misleading about what this
   section owns. */

/* Contrast lifts on shared components, scoped to this page. Each is a token
   swap, not a new colour. */
.uc-page .callout--warning .callout__title { color: var(--cc-gray-900); }
.uc-page .callout--urgent .callout__title  { color: var(--cc-red-dark); }
.uc-page .field-error                      { color: var(--cc-red-dark); }
/* The claim badges spanned 5.91:1 to 10.12:1 and the word that decides a
   claim — "Not approved" — was the palest ink on the page. Token swaps only. */
.uc-page .badge--red     { color: var(--cc-red-dark); }   /* 9.16:1 on --cc-red-light */
.uc-page .badge--neutral { color: var(--cc-gray-700); }   /* 8.84:1 on --cc-gray-100 */

/* ── 43. Claim wizard (public.js — routes/unclaimed.js) ────────────────────
   The document the server sends is the form it has always been: one scrolling
   page, four visible fieldsets, one Send button. public.js is what hides the
   steps.

   NOTHING HERE HIDES A STEP BEHIND `.js`. A .js-gated display:none applies only
   after the deferred script lands, so the rule would outlive any failure of the
   script meant to reveal the content again. Content arrives visible and JS hides
   it; chrome arrives `hidden` and JS reveals it — the same direction as
   `.hero__controls` in §11a, whose comment records that the opposite was caught
   in a real no-JS browser run rather than by reading the code.

   Classes are namespaced .uc-wiz__* deliberately: `.uc-steps` in §42 already
   styles the "What happens" list, and colliding with it is how a later edit
   silently restyles the wrong thing. */

/* The step heading lives INSIDE the <legend>, so one string is both the group
   label and the focus target and no copy is written twice. Reset to the
   legend's own scale — an h3 is 25.4px with a 16px bottom margin. */
/* Explicit, not inherited: steps 1-4 sit inside a <legend> (navy) and step 5
   does not, so `color: inherit` made the last heading body-ink and the set
   looked like two different things. */
/* A REAL RANK, not `font: inherit`. That reset computed to 16px Inter 700 —
   byte-identical to the bare `legend` rule at section 24 and one weight-step
   from `.field label` directly beneath it, so "3. Where should the county send
   the money?" was the same size, family and colour family as "Street address".
   INTER, NOT MERRIWEATHER, and that is the type rule for the whole module: the
   display face is the county SPEAKING (the banner h1, the answer to the search,
   the amount, the section labels), the UI face is the FORM'S OWN structure
   (step headings, field labels). Two things at the same --fs-3 never collide
   when they are in different families and different weights — the section label
   above this is Merriweather Black with a gold tick; this is Inter Bold with
   none. */
.uc-wiz__h {
  font-family: var(--font-ui);
  font-size: var(--fs-3);
  font-weight: var(--fw-bold);
  color: var(--cc-navy);                 /* 11.6:1 on white */
  line-height: var(--lh-tight);
  margin: 0;
}
/* .uc-wiz__pos gets no rule on purpose: "Step 2 of 5:" is part of the sentence,
   and the moment it becomes a coloured pill it stops reading as one. */

/* Only one step is on screen once the wizard runs, so `.uc-page fieldset +
   fieldset` (§42) would give steps 2-5 a top margin step 1 does not get, and the
   content would jump as you move between them. */
.js .uc-page .uc-form [data-uc-step] { margin-top: 0; }
/* fieldset carries margin-bottom from §24; the review <div> does not, so the nav
   would sit higher on step 5 than on every other step. */
.uc-wiz__review { margin-bottom: var(--space-5); }

/* Progress: numbered pills. The WORDS live in the step heading and are copied
   into each item's accessible name by JS at build time — there is no second copy
   of any title in the markup or in this file. Compact enough that 320px needs no
   special case. */
.uc-wiz__progress {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  list-style: none; margin: 0 0 var(--space-5); padding: 0;
}
.uc-wiz__progress[hidden] { display: none; }
.uc-wiz__progress li {
  display: flex; align-items: center; justify-content: center;
  min-width: 2.25rem; min-height: 2.25rem; padding: 0 var(--space-2);
  font-size: var(--fs-meta); font-weight: var(--fw-semibold);
  color: var(--color-text-muted);          /* the 10:1 grey .uc-page re-points */
  /* --color-border is decorative at 1.46:1 against the page; a control
     boundary needs to be a real one. */
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-surface);
}
/* Three states, three cues, and not one of them hue alone. Before this, "done"
   differed from "not yet done" by two colour properties and nothing else. The
   WORDS already exist — public.js writes "Completed: " / "Not yet done: " into
   a .visually-hidden span — so screen readers were fine and everybody else got
   two shades of dark blue-grey. */
.uc-wiz__progress li[data-state="done"] {
  color: var(--cc-navy);                 /* 10.1:1 on --cc-navy-light */
  background: var(--cc-navy-light);
  border-color: var(--cc-navy-mid);
}
/* Decoration reinforcing the fill. The STATE is in the visually-hidden span, so
   nothing depends on this glyph rendering. */
.uc-wiz__progress li[data-state="done"]::after {
  content: "\2713"; margin-left: 0.15em; font-size: 0.85em;
}
.uc-wiz__progress li[aria-current="step"] { color: var(--color-text-invert);
  background: var(--cc-navy); border-color: var(--cc-navy); }
.uc-wiz__progress li[data-state="bad"]    { color: var(--cc-red-dark);
  background: var(--cc-red-light); border-color: var(--cc-red-dark); }
/* A step can be BOTH current and invalid, and the two rules above then painted
   --cc-red-dark on the navy current fill: 1.16:1, an invisible number on the one
   pill the visitor most needs to find. Give the combination its own opaque
   pairing rather than letting two independent rules collide. */
.uc-wiz__progress li[data-state="bad"][aria-current="step"] {
  color: var(--color-text-invert); background: var(--cc-red-dark);
  border-color: var(--cc-red-dark);
}

/* DOM order is Back then Next and the visual order matches, so focus order is
   not reordered by flex. Next is pushed right by margin, not by `order`. */
.uc-wiz__nav { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center;
  margin-top: var(--space-6); }
.uc-wiz__nav[hidden] { display: none; }
.uc-wiz__nav .btn { min-height: 44px; }
.uc-wiz__nav [data-uc-next] { margin-left: auto; }
/* BOTH buttons, not just Back. `.btn { display: inline-flex }` is (0,1,0) and
   beats the UA sheet's `[hidden] { display: none }` (0,0,0), so hiding Next on
   the review step left a visible, tabbable, DEAD "Next" beside "Send my claim".
   Written against .btn so a third nav button can never be added without the
   guard. Same class of trap as .field-error[hidden] in §24. */
.uc-wiz__nav .btn[hidden] { display: none; }
@media not all and (min-width: 480px) {
  .uc-wiz__nav .btn { width: 100%; }
  .uc-wiz__nav [data-uc-next] { margin-left: 0; }
}

/* The review reuses .uc-facts from §42, already a real two-column definition
   grid on this page — no new component. */
.uc-wiz__review .contact-row dd { display: flex; flex-wrap: wrap;
  gap: var(--space-3); justify-content: space-between; align-items: baseline; }
.uc-wiz__val { min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; }
.uc-wiz__change { white-space: nowrap; }

/* Insurance, not a fix: a bare <fieldset hidden> and <div hidden> already
   compute to display:none. This is what stops all five steps appearing at once
   the first time somebody gives a step a grid or flex display — the exact bug
   already hit and fixed for .hero__controls. */
.uc-form [data-uc-step][hidden], .uc-submit[hidden] { display: none; }

/* Hidden steps are invisible to find-in-page and to print, and this audience
   prints things. Paper gets the whole form back, minus the chrome. */
@media print {
  /* Un-hide the STEPS only — scoped to fieldset so the review panel is not
     caught by it. The review is a rebuilt copy of every answer, including the
     Social Security box and the home address, and the un-hide selector was
     (0,3,0) against the suppression's (0,1,0), so paper got the lot. */
  .uc-form fieldset[data-uc-step][hidden] { display: block !important; }
  .uc-submit[hidden] { display: block !important; }
  .uc-form .uc-wiz__review[data-uc-step] { display: none !important; }
  .uc-wiz__nav, .uc-wiz__progress { display: none !important; }
}

/* ════════════════════════════════════════════════════════════════════════════
   41. THE COURTHOUSE PHOTOGRAPH UNDER AN EMERALD BRAND          [2026-09-02]

   The county's brand moved from navy to deep emerald. The two photographic
   surfaces — the homepage hero and every page banner — put a scrim OVER a
   picture of the courthouse against a bright Texas sky, and the page banner's
   scrim is only .68 opaque at its top edge. Under navy that never showed: navy
   over blue sky is navy. Under emerald the sky punched through the thinner
   part of the gradient and the banner read green on the left and blue-grey on
   the right, which is the one thing a brand colour must not do.

   The fix is to let the photograph contribute its LUMINANCE and take its hue
   from the brand: blending it against the brand's own darkest ink means the
   masonry, the clock face and the sky all keep their shape and tonal range
   while the colour comes from the county. Nothing is recoloured by hand and no
   new asset is needed — the same JPEG now reads emerald on an emerald site and
   would read navy again if the tokens went back.

   NOT applied to .hero__bg--tone: that slide is a flat brand gradient with no
   photograph in it, and blending a gradient against a flat colour would just
   flatten the gradient.
   ════════════════════════════════════════════════════════════════════════════ */
.page-banner {
  background-blend-mode: normal, luminosity, normal;
}
.hero__bg:not(.hero__bg--tone) {
  background-color: var(--cc-navy-dark);
  background-blend-mode: luminosity;
}

/* ════════════════════════════════════════════════════════════════════════════
   42. SIDE NAVIGATION RAIL, ANNOUNCEMENTS, SOCIAL FEED          [2026-09-02]

   Three content blocks: blocks/side-nav.js, blocks/announcements.js and
   blocks/social-feed.js. Announcements borrows the news-list markup whole
   (§23), so its only rule here is the optional "Read more" line. The side
   navigation is a card-like rail the renderer hoists into .page-layout__aside;
   the same markup reads correctly inline. The social feed is a Follow button,
   pasted posts and, for Facebook, a click-to-load box that requests nothing
   from Facebook until the visitor presses the button (public.js, "Social
   feed click-to-load"). Every colour is a token; every class a renderer
   emits has a rule below (tools/css-coverage.mjs).
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 42.1 the rail layout the renderer wraps around a hoisted side-nav ──── */
/* <div class="page-content"><div class="page-layout page-layout--rail">
     <div class="page-layout__main">…blocks…</div>
     <aside class="page-layout__aside">…side-nav…</aside></div></div>
   The grid is §26: one column, then main + rail at 1024px. The rail comes
   AFTER main in source order, so on a phone it stacks below the content it
   navigates. What §10 gives a top-level block — the page column, the side
   padding, the block-to-block rhythm — this wrapper now supplies, because
   the blocks are no longer direct children of .page-content. */
.page-content > .page-layout--rail {
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
.page-layout--rail { --rail: 18rem; }
.page-layout--rail .page-layout__main > .block + .block { margin-top: var(--space-6); }
.page-layout--rail .page-layout__main > .blk--width-content { max-width: var(--content-width); }
.page-layout--rail .page-layout__main > .blk--space-tight + .block,
.page-layout--rail .page-layout__main > .block + .blk--space-tight { margin-top: var(--space-3); }
.page-layout--rail .page-layout__main > .blk--space-loose + .block,
.page-layout--rail .page-layout__main > .block + .blk--space-loose { margin-top: var(--space-10); }
@media print {
  .page-content > .page-layout--rail { padding-inline: 0; }
}

/* ── 42.2 side navigation ──────────────────────────────────────────────── */
/* A card. The current page is the one item with a brand-coloured left edge,
   a tinted fill AND a heavier weight — three signals, so colour is never the
   only one. Contrast on the tint: link emerald on --cc-navy-xlight 7.2:1,
   deep emerald 14:1 (test/new-blocks.test.js reads the tokens and checks). */
.side-nav {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-4) 0 var(--space-3);
  overflow-wrap: anywhere;
}
.side-nav__title {
  font-family: var(--font-ui);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  color: var(--color-heading);
  margin: 0 var(--space-5) var(--space-3);
}
.side-nav__list, .side-nav__sub { list-style: none; margin: 0; padding: 0; }
.side-nav__link {
  display: block;
  min-height: 44px;
  padding: var(--space-3) var(--space-5);
  border-left: 3px solid transparent;
  color: var(--color-link);
  text-decoration: none;
}
.side-nav__link:hover { background: var(--cc-navy-xlight); text-decoration: underline; }
.side-nav__link--current,
.side-nav__link[aria-current="page"] {
  border-left-color: var(--cc-navy);
  background: var(--cc-navy-xlight);
  color: var(--cc-navy-dark);
  font-weight: var(--fw-semibold);
}
/* Nested pages indent the text, not the edge, so the current marker stays
   flush with the card whichever level it is on. */
.side-nav__sub .side-nav__link { padding-left: var(--space-8); }
/* Inline (a second side-nav, or one on a page with no rail): a column of
   links the full width of the page column would read as a sitemap. */
.page-content > .block-side-nav > .side-nav { max-width: 28rem; }

/* ── 42.3 announcements: the optional "Read more" line ─────────────────── */
.news-card__more { margin: 0; font-weight: var(--fw-semibold); }
.news-card__more a { color: var(--color-link); }
.news-card__more a::after { content: " →"; }

/* ── 42.4 social feed ──────────────────────────────────────────────────── */
.social-feed { max-width: var(--content-width); overflow-wrap: anywhere; }
.social-feed__title { margin: 0; }
.social-feed__actions { margin: 0 0 var(--space-5); }
.social-feed__follow { text-decoration: none; }
.social-feed__posts {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--space-4);
}
.social-feed__post {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cc-navy);
  border-radius: var(--radius);
  box-shadow: var(--shadow-1);
  padding: var(--space-4) var(--space-5);
}
.social-feed--facebook .social-feed__post { border-left-color: var(--cc-navy); }
.social-feed--x .social-feed__post { border-left-color: var(--cc-gray-900); }
.social-feed__text { margin: 0 0 var(--space-2); }
.social-feed__meta, .social-feed__note {
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--fs-meta);
}
.social-feed__note { margin-top: var(--space-4); }

/* The click-to-load box. Its height is a CLASS STEP (300–900 by hundreds),
   never an inline style (CMS-SPEC §22.1 refuses style attributes). The exact
   height the editor chose still reaches the frame: public.js reads
   data-social-height and sets the frame's height attribute, and the plugin
   URL carries it too. */
.social-embed {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
  background: var(--color-surface-tint);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-5);
}
.social-embed--h300 { min-height: 300px; }
.social-embed--h400 { min-height: 400px; }
.social-embed--h500 { min-height: 500px; }
.social-embed--h600 { min-height: 600px; }
.social-embed--h700 { min-height: 700px; }
.social-embed--h800 { min-height: 800px; }
.social-embed--h900 { min-height: 900px; }
.social-embed__notice { margin: 0; }
.social-embed__load { align-self: flex-start; }
.social-embed__noscript { margin: 0; }
/* Once the visitor has asked for it, the frame fills the box edge to edge. */
.social-embed--loaded { padding: 0; gap: 0; background: var(--color-surface); overflow: hidden; }
.social-embed iframe { display: block; width: 100%; border: 0; }
.social-embed--h300 iframe { height: 300px; }
.social-embed--h400 iframe { height: 400px; }
.social-embed--h500 iframe { height: 500px; }
.social-embed--h600 iframe { height: 600px; }
.social-embed--h700 iframe { height: 700px; }
.social-embed--h800 iframe { height: 800px; }
.social-embed--h900 iframe { height: 900px; }

/* ════════════════════════════════════════════════════════════════════════════
   43. THE SIDE-MENU RAIL — page-level layout for a hoisted side-nav block
                                                                  [2026-09-03]
   services/renderer.js lifts the FIRST side-nav block out of the block run
   and emits, inside the ordinary .page-content:

       <div class="page-content page-content--rail">
         <div class="page-layout page-layout--rail">
           <div class="page-layout__main"> …every other block… </div>
           <aside class="page-layout__aside" aria-label="Section menu"> …nav… </aside>
         </div>
       </div>

   WHY THE COLUMN NEEDS RULES OF ITS OWN. Section 10 gives every block its page
   column with '.page-content > .block' — a DIRECT-child selector. Inside the
   rail grid the blocks are one level deeper, so they would lose their
   padding and their block-to-block rhythm. This section restates exactly
   those two things for '.page-layout__main > .block', and turns OFF the
   per-block max-width and centring, because the grid column is now the
   measure. Full-bleed blocks ('.block--full') are contained to the column on
   a rail page: a rail and a full-bleed band cannot coexist, and the column
   is the honest answer.

   The grid itself is section 26's '.page-layout'; only the width of the rail
   is set here ('--rail', 18rem — a menu, not an advisory paragraph like
   /unclaimed's 26rem). Below --bp-lg (1024px) '.page-layout' is already a
   single column, and the aside is AFTER the main column in source order, so a
   phone reads the page first and the menu after it — the same order a
   screen reader gets on every width.
   ════════════════════════════════════════════════════════════════════════════ */
.page-content--rail > .page-layout--rail {
  --rail: 18rem;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
.page-layout--rail .page-layout__main > .block {
  max-width: none;
  margin-inline: 0;
  padding-inline: 0;
}
.page-layout--rail .page-layout__main > .block + .block { margin-top: var(--space-6); }
.page-layout--rail .page-layout__main > .block--full { max-width: none; padding-inline: 0; }
/* The aside is a landmark with a heading of its own; it takes no top margin
   at desktop (it sits level with the first block) and the standard block gap
   when it stacks below the content on a narrower screen. */
.page-layout--rail .page-layout__aside { margin-top: var(--space-6); }
@media (min-width: 1024px) {
  .page-layout--rail .page-layout__aside { margin-top: 0; }
}

/* ════════════════════════════════════════════════════════════════════════════
   44. PUBLIC FORMS — services/forms/render.js                    [2026-09-02]

   The one renderer for every form a resident fills in: the form block, the
   standalone /forms/<key> page and the error re-render all emit the same
   small, fixed vocabulary — .ccw-form, .form-field, .form-label, .form-hint,
   .form-error, .form-error-summary, .form-fieldset, .form-legend,
   .form-choice, .form-date, .form-file, .form-actions, .form-confirm,
   .form-closed, .form-honeypot — and every one of them has a rule here
   (tools/css-coverage.mjs; test/forms-public.test.js is its static shadow).

   WHAT IT LEANS ON. The controls themselves are section 24's: the same
   border, radius, 44px height, 16px floor and red aria-invalid ring as every
   other input on the site, with section 2's focus ring. The submit button
   is section 12's .btn--primary. The closed notice and the "only one form"
   notice are section 15 callouts. Nothing is restyled; this section lays
   the pieces out.

   THE SHAPE. One reading column of 40rem: wide enough for two half-width
   questions side by side from 768px (a phone gets one column), narrow
   enough that a long-answer box keeps a comfortable measure. A section (the
   clerk's "Section heading" card) is a bordered box with its title as the
   legend; the fieldsets a single question needs — radios, tick boxes, the
   three date boxes, an address — are borderless with the legend styled as
   a label, so a resident sees questions, not boxes inside boxes.

   ERRORS are the GOV.UK pattern the renderer emits: a red-edged summary at
   the top that takes focus, then a red edge and a red message on each
   failing question. Colour is never the only signal: the summary says
   "There is a problem", the inline message begins with a hidden "Error:",
   the required marker is the word "(required)".

   THE HONEYPOT is moved off-screen on screen media — never display:none or
   visibility:hidden, because automated programs fill fields they cannot
   see but skip fields the page has removed. A screen reader already
   ignores it: aria-hidden and tabindex=-1 come from the renderer. Print
   drops it together with the button.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 44.1 the column ─────────────────────────────────────────────────────── */
/* A typed web address echoed back into the summary must not force 320px
   overflow (WCAG 1.4.10), so the block and the form both wrap anywhere. */
.block-form { overflow-wrap: anywhere; }
.ccw-form {
  --form-measure: 40rem;
  max-width: var(--form-measure);
  overflow-wrap: anywhere;
}
.ccw-form__intro { margin: 0 0 var(--space-6); }
/* The "signed-in county staff" note the renderer puts above a staff form. */
.ccw-form > .form-hint { margin: 0 0 var(--space-5); }

/* ── 44.2 one question ───────────────────────────────────────────────────── */
.form-field { margin: 0 0 var(--space-5); min-width: 0; }
.form-field--half { min-width: 0; }
.form-label {
  display: block;
  font-weight: var(--fw-semibold);
  color: var(--cc-navy-dark);
  margin: 0 0 var(--space-1);
}
/* "(required)" is the signal; the lighter weight keeps the question itself
   the loudest thing on the line. --color-text-muted is 7.0:1 on white. */
.form-required { font-weight: var(--fw-regular); color: var(--color-text-muted); }
.form-hint, .form-file__note { color: var(--color-text-muted); margin: 0 0 var(--space-2); }
.form-error {
  color: var(--cc-red);
  font-weight: var(--fw-semibold);
  margin: 0 0 var(--space-2);
}
/* Number-shaped answers get a box the size of the answer; everything else
   fills the column (section 24 sets width: 100%). */
.form-field > input[inputmode="numeric"], .form-field > input[inputmode="decimal"] { max-width: 12rem; }
.form-field > input[autocomplete="address-level1"] { max-width: 6rem; }
.form-field > input[autocomplete="postal-code"] { max-width: 10rem; }

/* ── 44.3 groups: radios, tick boxes, dates, addresses, sections ─────────── */
/* A fieldset's default minimum size is its content, which would let a long
   option push the page sideways on a phone. */
.form-fieldset { min-width: 0; min-inline-size: 0; }
/* A single question's fieldset: no box, and the legend reads as a label. */
.form-field.form-fieldset { border: 0; padding: 0; margin: 0 0 var(--space-5); }
.form-field.form-fieldset > .form-legend {
  padding: 0;
  margin: 0 0 var(--space-1);
  font-family: var(--font-ui);
  font-size: var(--fs-0);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-body);
  color: var(--cc-navy-dark);
}
/* The parts of an address are ordinary questions inside the group, tighter. */
.form-field.form-fieldset > .form-field { margin-bottom: var(--space-4); }
.form-field.form-fieldset > .form-field:last-child { margin-bottom: 0; }

/* A section: the clerk's heading and sentence over a box of questions. */
.form-fieldset:not(.form-field) {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  padding: var(--space-5);
  margin: 0 0 var(--space-6);
}
.form-fieldset:not(.form-field) > .form-legend {
  padding-inline: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  color: var(--cc-navy);
}
.form-fieldset:not(.form-field) > .form-hint { margin-bottom: var(--space-5); }
.form-fieldset:not(.form-field) > :last-child { margin-bottom: 0; }

/* Radios and tick boxes: a 44px row, the box aligned with the first line of
   its label, the whole label a click target. Option labels are regular
   weight because the legend carries the question; a lone yes/no box IS the
   question, so its label keeps the label weight. */
.form-choice__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: 44px;
}
.form-choice__item > input {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  margin: 0.625rem 0 0;
  accent-color: var(--cc-navy);
  cursor: pointer;
}
.form-choice__item > .form-label {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding-block: var(--space-2);
  font-weight: var(--fw-regular);
  color: var(--color-text);
  cursor: pointer;
}
.form-choice:not(.form-fieldset) .form-choice__item > .form-label {
  font-weight: var(--fw-semibold);
  color: var(--cc-navy-dark);
}

/* A date is three labelled boxes in a row — month, day, year — each sized
   to the digits it takes. The year is the last part. */
.form-date > .form-date__part {
  display: inline-block;
  vertical-align: top;
  margin: 0 var(--space-3) 0 0;
}
.form-date__part > .form-label { font-weight: var(--fw-regular); color: var(--color-text); }
.form-date__part > input { width: 4.5em; }
.form-date__part:last-of-type > input { width: 6.5em; }

/* The file input is outside section 24's selector list (its own comment
   says so); this gives it the same box, and the browser's "Choose file"
   button the outline-button look. */
.form-file > input[type="file"] {
  display: block;
  width: 100%;
  max-width: 100%;
  font: inherit;
  font-size: max(16px, 1em);
  color: var(--color-text);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-surface);
}
.form-file > input[type="file"]::file-selector-button {
  font: inherit;
  font-weight: var(--fw-semibold);
  min-height: 36px;
  padding: 0 var(--space-4);
  margin-right: var(--space-4);
  border: 2px solid var(--cc-navy);
  border-radius: var(--radius);
  background: transparent;
  color: var(--cc-navy);
  cursor: pointer;
}
.form-file > input[type="file"]::file-selector-button:hover {
  background: var(--cc-navy);
  color: var(--color-text-invert);
}

/* ── 44.4 errors ─────────────────────────────────────────────────────────── */
/* A failing question gets a red left edge. Written AFTER the borderless
   group rule above, so a radio group, a date or an address takes it too. */
.form-field[data-invalid="true"] {
  border-left: 4px solid var(--cc-red);
  padding-left: var(--space-4);
}
.form-error-summary {
  border: 4px solid var(--cc-red);
  border-radius: var(--radius);
  background: var(--color-surface);
  padding: var(--space-4) var(--space-5);
  margin: 0 0 var(--space-6);
}
/* Focus arrives by autofocus or by script, never by Tab, so :focus-visible
   may not match; the ring sits on :focus so where the page went is seen. */
.form-error-summary:focus { outline: none; box-shadow: var(--focus-ring); }
.form-error-summary :is(h2, h3, h4, h5, h6) {
  font-family: var(--font-ui);
  font-size: var(--fs-2);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  color: var(--cc-red);
  margin: 0 0 var(--space-3);
}
.form-error-summary ul { margin: 0; padding-left: 1.4em; }
.form-error-summary li { margin-bottom: var(--space-1); }
.form-error-summary li:last-child { margin-bottom: 0; }
.form-error-summary a {
  color: var(--cc-red);
  font-weight: var(--fw-semibold);
  text-decoration: underline;
}
.form-error-summary a:hover { text-decoration-thickness: 2px; }

/* ── 44.5 the one button, the counter, the honeypot ──────────────────────── */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: var(--space-6) 0 0;
}
.form-submit { width: 100%; }
@media (min-width: 480px) {
  .form-submit { width: auto; min-width: 12rem; }
}
/* The "N characters left" line public.js adds AFTER a limited box. */
.form-counter { margin: var(--space-1) 0 0; }
.form-honeypot {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
/* Hidden by public.js when a "show when" rule says so. Section 24 learned
   that a display value of our own beats the browser's [hidden]; nothing in
   this section sets display on a wrapper, and this keeps it so even if a
   later section does. */
.ccw-form .form-field[hidden] { display: none; }

/* ── 44.6 two half-width questions side by side (768px and up) ───────────── */
/* The column and each section become a two-track grid; everything spans
   both tracks except a .form-field--half, so two halves in a row share it
   and an odd one keeps the left track. Below 768px there is no grid at all
   and the form is one column of block flow. */
@media (min-width: 768px) {
  .ccw-form, .form-fieldset:not(.form-field) {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-5);
    align-items: start;
  }
  .ccw-form > :not(.form-field--half),
  .form-fieldset:not(.form-field) > :not(.form-field--half) { grid-column: 1 / -1; }
}

/* ── 44.7 the closed notice and the confirmation ─────────────────────────── */
.form-closed { max-width: var(--content-width); }
.form-closed .callout__body :is(h2, h3, h4, h5, h6) {
  font-size: var(--fs-2);
  margin: 0 0 var(--space-2);
}
.form-confirm { max-width: var(--content-width); }
.form-confirm > p { margin: 0 0 var(--space-4); }
.form-confirm__ref { font-size: var(--fs-1); }
/* The reference number is the one thing to write down: monospace on the
   section wash, so it reads as a code and not as a word. Deep emerald on
   --cc-navy-xlight is 14:1. */
.form-confirm__ref strong {
  font-family: var(--font-mono);
  font-size: 1.05em;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--cc-navy-light);
  border-radius: var(--radius-sm);
  background: var(--cc-navy-xlight);
  color: var(--cc-navy-dark);
  white-space: nowrap;
}

/* ── 44.8 forced colours and print ───────────────────────────────────────── */
@media (forced-colors: active) {
  .form-error-summary:focus { outline: 3px solid Highlight; outline-offset: 2px; box-shadow: none; }
}
@media print {
  .form-actions, .form-honeypot, .form-counter { display: none !important; }
}
