/* deflockarvada.com — independent public-record site on Arvada, Colorado's Flock ALPR program */

:root {
  --ink: #0f1721;
  --ink-2: #16202c;
  --ink-3: #1d2938;
  --ink-band: #131c27;   /* alternating section ground, between --ink and --ink-2 */
  --line: #2b3a4d;
  --line-soft: #223044;
  --text: #dbe4ee;
  --text-dim: #93a6ba;
  --text-faint: #6f8ba6;
  --accent: #e2483d;
  --accent-soft: #f08a80;
  --amber: #e8b23a;

  /* Semantic aliases over the palette above. Amber was carrying four jobs by
     hex code alone. Measured, it carries two: "qualified or incomplete" inside
     the content area, and "act now" in the chrome around it. Those are not the
     same idea and should not have to share a name. Naming them lets either
     diverge later without hunting hex codes through the file. */
  --verdict-narrow: var(--amber);  /* a claim that is true but narrow */
  --record-gap:     var(--amber);  /* the record does not answer this */
  --notice:         var(--amber);  /* time-sensitive chrome, above the content */
  --demand:         var(--amber);  /* the footer demand lines */

  /* Chart marks. --bar-key points at --accent rather than repeating its hex,
     for the same reason the amber aliases do: one place to change it.
     --bar-context is a literal because it is a color the palette did not have,
     chosen for 3.49:1 against the table surface so it reads as a mark you can
     see rather than a hint. */
  --bar-key:     var(--accent);
  --bar-context: #55708a;
  --paper: #f6f4ef;
  --measure: 68ch;
  --wrap: 1120px;
  --serif: Georgia, "Iowan Old Style", "Times New Roman", serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 5.5rem; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; height: auto; }

a { color: var(--accent-soft); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: #fff; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: #fff; padding: .7rem 1.1rem; font-weight: 600;
}
.skip-link:focus { left: 0; }

:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 1.25rem; }

/* Hashes and file names run past the viewport on a phone if they are allowed
   to stay one word. They are the one place on this site where breaking mid-token
   is right: a SHA-256 is read character by character or not at all. */
code { overflow-wrap: anywhere; }

/* ---------- nav ---------- */

header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(15, 23, 33, .94);
  backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--line-soft);
}

.nav {
  position: relative;
  max-width: var(--wrap); margin: 0 auto; padding: .55rem 1.25rem;
  display: flex; align-items: center; gap: 1rem;
}

.brand {
  display: inline-flex; align-items: center; color: var(--accent);
  text-decoration: none; border-radius: 8px; padding: .2rem;
  transition: color .15s ease, transform .15s ease;
}
.brand-mark { display: block; }
.brand:hover { color: var(--accent-soft); transform: rotate(-8deg); }
.brand:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; }

/* The menu is a disclosure at every width. A bare hamburger on a wide screen
   hurts discoverability, so the button is labeled; the word is what makes it
   findable, the bars are what make it recognisable. */
.nav-toggle {
  margin-left: auto; display: inline-flex; align-items: center; gap: .6rem;
  padding: .45rem .7rem .45rem .85rem;
  background: transparent; border: 1px solid var(--line); border-radius: 999px;
  color: var(--text-dim); cursor: pointer;
  font-family: var(--mono); font-size: .72rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; line-height: 1;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.nav-toggle:hover { color: var(--text); border-color: var(--text-faint); background: var(--ink-2); }
.nav-toggle:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; }
.nav-toggle[aria-expanded="true"] { color: var(--text); border-color: var(--text-faint); background: var(--ink-3); }
.nav-toggle-bars { display: flex; flex-direction: column; gap: 4px; width: 17px; }
.nav-toggle-bars span {
  display: block; height: 2px; background: currentColor; border-radius: 2px;
  transition: transform .18s ease, opacity .12s ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

#site-menu {
  position: absolute; top: calc(100% + .45rem); right: 1.25rem; z-index: 60;
  min-width: 240px; max-width: calc(100vw - 2.5rem);
  list-style: none; margin: 0; padding: .4rem;
  display: none; flex-direction: column;
  background: var(--ink-2); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, .5);
}
#site-menu.open { display: flex; }
#site-menu a {
  display: block; padding: .55rem .7rem; border-radius: 7px;
  color: var(--text-dim); text-decoration: none; font-size: .95rem; font-weight: 500;
}
#site-menu a:hover { background: var(--ink-3); color: #fff; }
#site-menu a:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: -2px; }
#site-menu a[aria-current="page"] {
  color: #fff; background: var(--ink-3);
  box-shadow: inset 2px 0 0 var(--accent);
}

@media (max-width: 560px) {
  .nav-toggle-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .nav-toggle { padding: .5rem .6rem; }
  #site-menu { right: 1rem; left: 1rem; min-width: 0; max-width: none; }
}

.council-banner {
  margin: 0; padding: .8rem 1.25rem; text-align: center; max-width: none;
  background: rgba(232,178,58,.13); border-bottom: 1px solid rgba(232,178,58,.45);
  color: var(--text); font-size: .95rem; line-height: 1.45;
}
.council-banner strong { color: var(--notice); letter-spacing: .04em; text-transform: uppercase; font-size: .82rem; }
.council-banner a { color: #fff; font-weight: 600; text-decoration-color: var(--notice); }
.council-banner a:hover, .council-banner a:focus-visible { color: var(--notice); }
/* The bar is full-bleed so the amber reaches both edges, but the sentence inside it
   is prose and needs a measure. Without this the notice sets one long centred line
   across a wide monitor. */
.council-banner-inner { display: block; max-width: var(--wrap); margin: 0 auto; }

.watchdog-banner {
  margin: 0; padding: .5rem 1.25rem; text-align: center; max-width: none;
  background: var(--ink-2); border-bottom: 1px solid var(--line-soft);
  font-size: .8rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint);
}

/* ---------- hero ---------- */

.hero {
  border-bottom: 1px solid var(--line-soft);
  background:
    radial-gradient(1100px 460px at 78% -10%, rgba(226,72,61,.16), transparent 62%),
    linear-gradient(180deg, var(--ink-2), var(--ink));
  padding: clamp(2.75rem, 7vw, 5rem) 0 clamp(2.25rem, 5vw, 3.5rem);
}

.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
}
.hero-content { min-width: 0; }

.hero-media {
  margin: 0; min-width: 0;
}
.hero-media img {
  display: block; width: 100%; height: auto;
  border-radius: 12px; border: 1px solid var(--line);
  background: var(--ink-2);
  box-shadow: 0 18px 48px -18px rgba(0, 0, 0, .7);
}
.hero-media figcaption {
  margin-top: .7rem; font-size: .78rem; line-height: 1.55;
  color: var(--text-faint);
}

/* Hero carousel: arrows over the artwork, dots beneath. All controls are
   JS-built, so a no-JS page renders only the static noscript image. */
.hero-carousel { position: relative; }
.hero-carousel img { transition: opacity .28s ease; }
.hero-carousel img.swapping { opacity: .4; }

.hero-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line); background: rgba(15, 23, 33, .72);
  color: var(--text); cursor: pointer;
}
.hero-arrow:hover { background: rgba(29, 41, 56, .96); color: #fff; }
.hero-arrow.prev { left: .6rem; }
.hero-arrow.next { right: .6rem; }

.hero-dots {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: .15rem; margin-top: .55rem;
}
/* 11px dot inside a 23px hit target: the padding pads the tap area and
   background-clip keeps the visible dot small. */
.hero-dots button {
  width: 11px; height: 11px; box-sizing: content-box; padding: 6px;
  border: 0; border-radius: 50%; background: var(--line);
  background-clip: content-box; cursor: pointer;
}
.hero-dots button:hover { background-color: var(--text-faint); }
.hero-dots button[aria-current="true"] { background-color: var(--accent-soft); }

/* Click-to-enlarge: an invisible button over the artwork (the arrows come
   later in the DOM, so they stack above it and stay clickable) opens the
   current cartoon in a full-screen lightbox. Any click on the overlay, its
   close button, or Escape closes it. */
.hero-zoom {
  position: absolute; inset: 0; width: 100%; height: 100%;
  padding: 0; border: 0; border-radius: 12px;
  background: transparent; cursor: zoom-in;
}

.hero-lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(1rem, 4vw, 2.5rem);
  background: rgba(10, 17, 25, .93);
  cursor: zoom-out;
  animation: lightbox-in .18s ease;
}
@keyframes lightbox-in { from { opacity: 0; } }
.hero-lightbox picture { display: contents; }
.hero-lightbox img {
  width: auto; height: auto; max-width: 100%; max-height: 100%;
  border-radius: 12px; border: 1px solid var(--line);
  background: var(--ink-2);
  box-shadow: 0 24px 72px -20px rgba(0, 0, 0, .9);
}
.hero-lightbox-close {
  position: absolute; top: .9rem; right: .9rem;
  display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line); background: rgba(15, 23, 33, .72);
  color: var(--text); cursor: pointer;
}
.hero-lightbox-close:hover { background: rgba(29, 41, 56, .96); color: #fff; }

body.lightbox-open { overflow: hidden; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .hero-media { order: -1; margin-bottom: .5rem; }
}

.hero-brand {
  font-family: var(--mono); font-size: .8rem; letter-spacing: .17em;
  text-transform: uppercase; color: var(--accent-soft); margin: 0 0 1rem;
}

.hero-titles {
  font-family: var(--serif); font-weight: 700;
  font-size: clamp(2rem, 5.6vw, 3.5rem); line-height: 1.1;
  margin: 0 0 1.4rem; letter-spacing: -.015em; max-width: 20ch;
}
.hero-titles span { display: block; }
.hero-titles span:last-child { color: var(--accent-soft); }

.lede {
  font-size: clamp(1.04rem, 1.6vw, 1.2rem); line-height: 1.62;
  max-width: 60ch; color: var(--text); margin: 0 0 1.75rem;
}

.cta-group { display: flex; flex-wrap: wrap; gap: .7rem; margin: 0 0 1.5rem; }

.cta {
  display: inline-block; padding: .68rem 1.3rem; border-radius: 7px;
  background: var(--accent); color: #fff; text-decoration: none;
  font-weight: 600; font-size: .95rem; border: 1px solid var(--accent);
}
.cta:hover { background: #c93a30; color: #fff; }
.cta.ghost { background: transparent; color: var(--text); border-color: var(--line); }
.cta.ghost:hover { background: var(--ink-3); color: #fff; border-color: var(--text-faint); }

.hero-caption {
  font-size: .84rem; line-height: 1.6; color: var(--text-faint);
  max-width: 78ch; margin: 0; padding-top: 1.25rem; border-top: 1px solid var(--line-soft);
}

/* Homepage cartoon. One of ten is chosen at random in the markup; the
   keyboard easter egg opens a separate Blucifer set. The caption says the
   scene is invented so it cannot be read as a record photograph. */
.cartoon {
  margin: 0 auto clamp(1.75rem, 4vw, 2.75rem);
  width: min(760px, calc(100% - 2.5rem));
  display: flex;
  flex-direction: column;
  align-items: center;
}
.cartoon picture { display: contents; }
.cartoon img {
  display: block; width: 100%; height: auto;
  border-radius: 12px; border: 1px solid var(--line);
  background: var(--ink-2);
  box-shadow: 0 18px 48px -18px rgba(0, 0, 0, .7);
}
.cartoon figcaption {
  margin: .8rem 0 0; max-width: 52ch;
  font-size: .78rem; line-height: 1.5; color: var(--text-faint);
  text-align: center;
}

/* ---------- sections ---------- */

section { padding: clamp(2.75rem, 5.5vw, 4.25rem) 0; }

/* Alternating ground. On a twenty-screen page a hairline rule between sections
   is not enough of a landmark: the eye has nothing to hold while scrolling and
   every section reads as equally dense. A ground that shifts gives the page a
   beat, and costs no ink.

   The band REPLACES the rule rather than joining it. With strict alternation
   every boundary is already a color change, so a border on top of it is two
   separators doing one separator's job, which is the doubled ink that makes a
   dense page feel noisy. All of them come off.

   --ink-band sits between --ink and --ink-2: far enough to register, close
   enough not to read as stripes. The hero and page-head paint their own
   gradients and are unaffected, both being first-of-type and therefore odd. */
main > section:nth-of-type(even) { background: var(--ink-band); }

.kicker {
  display: block; font-family: var(--mono); font-size: .74rem;
  letter-spacing: .17em; text-transform: uppercase; color: var(--accent-soft);
  margin-bottom: .6rem;
}

h1, h2, h3, h4 { font-family: var(--serif); letter-spacing: -.01em; }
h2 { font-size: clamp(1.5rem, 3vw, 2.05rem); line-height: 1.2; margin: 0 0 1rem; }
h3 { font-size: 1.2rem; margin: 2rem 0 .6rem; }
h4 { font-size: 1.02rem; margin: 1.4rem 0 .4rem; color: var(--text); }

p { max-width: var(--measure); }
.section-sub { color: var(--text-dim); max-width: 66ch; font-size: 1.02rem; }

.page-head { padding: clamp(2.25rem, 5vw, 3.25rem) 0 clamp(1.5rem, 3vw, 2rem); background: linear-gradient(180deg, var(--ink-2), var(--ink)); border-bottom: 1px solid var(--line-soft); }
.page-head h1 { font-size: clamp(1.85rem, 4.4vw, 2.85rem); line-height: 1.14; margin: 0 0 .85rem; max-width: 24ch; }
.page-head .lede { margin-bottom: 0; }

/* ---------- at a glance ---------- */

.atglance ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .85rem; }
.atglance li {
  background: var(--ink-2); border: 1px solid var(--line-soft);
  border-left: 3px solid var(--accent); border-radius: 0 8px 8px 0;
  padding: 1rem 1.15rem; max-width: none;
}
.atglance li strong:first-child { color: #fff; }

/* ---------- stat grid ---------- */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); gap: .9rem; margin: 1.75rem 0 0; }
.stat {
  background: var(--ink-2); border: 1px solid var(--line-soft); border-radius: 9px;
  padding: 1.15rem 1.2rem;
}
.stat .n {
  display: block; font-family: var(--serif); font-weight: 700;
  font-size: clamp(1.9rem, 4vw, 2.5rem); line-height: 1; color: var(--accent-soft);
  margin-bottom: .45rem;
}
.stat .l { display: block; font-size: .89rem; color: var(--text-dim); line-height: 1.45; }

/* ---------- figures ---------- */

figure { margin: 1.75rem 0; }
figure img, figure svg { display: block; width: 100%; border-radius: 9px; border: 1px solid var(--line); background: var(--ink-2); }
/* The ALPR map embeds as an <object> so its per-camera links work; unlike an
   img it needs the aspect ratio stated to size before (or without) its data. */
figure object.alpr-map {
  display: block; width: 100%; height: auto; aspect-ratio: 1600 / 911;
  border-radius: 9px; border: 1px solid var(--line); background: var(--ink-2);
}
figcaption { font-size: .85rem; color: var(--text-faint); line-height: 1.6; margin-top: .7rem; max-width: 80ch; }

/* The way out of a map that has been scaled below the size of its own targets.
   Hidden wherever the dots are big enough to hit, which is every pointer that
   is not a finger and every screen with room for the map at something near its
   own scale. */
.map-escape { display: none; }
@media (pointer: coarse), (max-width: 700px) {
  .map-escape { display: block; margin: .75rem 0 0; max-width: none; }
  .map-escape a {
    display: inline-flex; align-items: center; gap: .45rem;
    min-height: 44px; padding: .55rem 1rem;
    border: 1px solid var(--line); border-radius: 7px;
    background: var(--ink-2); color: var(--text);
    text-decoration: none; font-size: .9rem; font-weight: 600;
  }
  .map-escape a::after { content: "\2197"; color: var(--accent-soft); }
}
@media print { .map-escape { display: none; } }

/* A document exhibit: a light-background record shown on the dark page. Capped
   well below its pixel width so the asset renders above 1x on every screen. */
.exhibit { max-width: 560px; }
.exhibit img { background: var(--paper); }
.exhibit > a { display: block; border-radius: 9px; }
.exhibit > a:hover img, .exhibit > a:focus-visible img { border-color: var(--accent-soft); }
.transcript {
  background: var(--ink-2); border: 1px solid var(--line-soft); border-left: 3px solid var(--line);
  border-radius: 9px; padding: 1.15rem 1.35rem; margin: 1.5rem 0; max-width: 74ch;
}
.transcript blockquote { margin: 0; max-width: none; }
.transcript p { max-width: none; }
.transcript p:first-of-type { margin-top: 0; }
.transcript p:last-child { margin-bottom: 0; }
.transcript .label {
  display: block; font-size: .74rem; letter-spacing: .09em; text-transform: uppercase;
  font-weight: 700; color: var(--text-faint); margin-bottom: .55rem;
}

/* ---------- timeline ---------- */

.timeline { list-style: none; margin: 2rem 0 0; padding: 0 0 0 1.9rem; position: relative; max-width: 82ch; }
.timeline::before { content: ""; position: absolute; left: 6px; top: .4rem; bottom: .4rem; width: 2px; background: var(--line); }

.timeline > li { position: relative; padding: 0 0 1.9rem; }
.timeline > li::before {
  content: ""; position: absolute; left: -1.9rem; top: .42rem;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--ink); border: 3px solid var(--text-faint);
}
.timeline > li.key::before { border-color: var(--accent); background: var(--accent); }
.timeline .date {
  display: block; font-family: var(--mono); font-size: .78rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-soft); margin-bottom: .25rem;
}
.timeline .t { display: block; font-family: var(--serif); font-size: 1.12rem; font-weight: 700; color: #fff; margin-bottom: .35rem; line-height: 1.35; }
.timeline p { margin: 0; color: var(--text); max-width: none; }
.timeline li p + p { margin-top: .6rem; }
.timeline .tag {
  display: inline-block; font-family: var(--mono); font-size: .68rem; letter-spacing: .08em;
  text-transform: uppercase; padding: .12rem .45rem; border-radius: 4px; margin-left: .45rem;
  vertical-align: .12em; background: var(--ink-3); color: var(--text-dim); border: 1px solid var(--line);
}
.timeline .tag.co { color: var(--accent-soft); border-color: rgba(226,72,61,.4); }

/* ---------- callouts ---------- */

.note, .gap {
  border-radius: 9px; padding: 1.1rem 1.25rem; margin: 1.75rem 0;
  max-width: 80ch; font-size: .96rem;
}
.note { background: var(--ink-2); border: 1px solid var(--line); border-left: 3px solid var(--text-faint); }
.gap  { background: rgba(232,178,58,.06); border: 1px dashed rgba(232,178,58,.34); border-left: 3px dashed var(--record-gap); }
.note p, .gap p { max-width: none; }
.note p:first-child, .gap p:first-child { margin-top: 0; }
.note p:last-child, .gap p:last-child { margin-bottom: 0; }
.gap .label, .note .label {
  display: block; font-family: var(--mono); font-size: .72rem; letter-spacing: .13em;
  text-transform: uppercase; margin-bottom: .45rem;
}
.gap .label { color: var(--record-gap); }
.note .label { color: var(--text-faint); }

/* ---------- ALPR-vs-Flock explainer (program page) ----------

   Two mix-ups feed each other in Lakewood: that "ALPR" and "Flock" name the
   same machine, and that a Flock pole on a city street is the city's camera.
   Both get one figure here, and both are plain HTML rather than an SVG: they
   reflow on a phone instead of scaling their own type down to nothing, they
   keep every number selectable and citable, and they print. The same
   comparison ships as images/alpr-vs-flock.svg for people who need to post a
   picture somewhere this page cannot go.

   The ladder is a "plus", not a "versus". The left column is the part the city
   is right about, so it gets the ordinary card treatment; the accent is spent
   entirely on the right column, which is what actually arrived in 2025. Its
   list continues the left one's numbering (start="4") because these are three
   more steps on the same machine, not three alternatives to it -- and native
   <ol> markers carry that through printing and through a stylesheet that never
   loads, which CSS counters would not.
   --------------------------------------------------------------------------- */

.ladder { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1.5rem 0 0; align-items: start; }
@media (max-width: 760px) { .ladder { grid-template-columns: 1fr; } }

/* Each card takes its own height. The two lists are far enough apart in
   length that a shared bottom edge left the shorter one holding a visible
   hole. */
.ladder > div {
  background: var(--ink-2); border: 1px solid var(--line-soft);
  border-radius: 9px; padding: 1.15rem 1.3rem;
}
.ladder > .plus {
  background: rgba(226, 72, 61, .05);
  border-color: rgba(226, 72, 61, .3); border-left: 3px solid var(--accent);
}
.ladder h4 { margin: 0; font-size: 1.04rem; color: var(--text); }
.ladder .when {
  display: block; margin: .3rem 0 1rem;
  font-family: var(--mono); font-size: .69rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-faint);
}
.ladder .plus .when { color: var(--accent-soft); }
.ladder ol { margin: 0 0 .35rem; padding-left: 1.5rem; }
.ladder li { margin-bottom: .8rem; padding-left: .3rem; font-size: .95rem; line-height: 1.55; }
.ladder li:last-child { margin-bottom: 0; }
.ladder li::marker { font-family: var(--mono); font-size: .82rem; color: var(--text-faint); }
.ladder .plus li::marker { color: var(--accent-soft); }
.ladder .sofar {
  margin: 1.05rem 0 0; padding-top: .95rem; border-top: 1px solid var(--line-soft);
  max-width: none; font-size: .87rem; line-height: 1.6; color: var(--text-dim);
}

/* The nesting bar: 67 mapped readers, of which 53 wear the Flock badge, of
   which 16 are the city's. Nested sets are what the numbers actually are, and
   a stacked proportional bar under a brace shows the nesting and the
   magnitudes at once -- the "one in four" is visible without arithmetic.
   The bar and brace are aria-hidden because the key below states every number
   in text; a screen reader should hear it once, not twice. */
.setbar { margin: 1.5rem 0 0; }
/* The key is prose and takes a prose measure; left to the 1120px wrap it was
   setting 140-character lines. */
.setbar-cap, .setbar-key { max-width: 78ch; }
.setbar-cap { margin: 0 0 .6rem; font-size: .95rem; color: var(--text-dim); }
.setbar-brace {
  position: relative; width: 79.1%;   /* 53 of 67 */
  margin-top: 1.9rem;                 /* room for the label above it */
  height: 11px; border: 1px solid var(--line); border-bottom: 0; border-radius: 5px 5px 0 0;
}
.setbar-brace-label {
  position: absolute; left: 0; bottom: calc(100% + .35rem); white-space: nowrap;
  font-family: var(--mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-faint);
}
.setbar-track { display: flex; height: 30px; border-radius: 3px; overflow: hidden; }
.seg {
  display: flex; align-items: center;
  width: var(--v); min-width: 32px; padding-left: .55rem;
  font-family: var(--mono); font-size: .78rem;
  print-color-adjust: exact; -webkit-print-color-adjust: exact;
}
.seg-city   { background: var(--accent); color: #fff; }
.seg-flock  { background: #8a3a36; color: #f0d5d2; }   /* Flock-branded, not the city's */
.seg-vendor { background: var(--bar-context); color: var(--ink); }
.setbar-key { list-style: none; margin: 1.1rem 0 0; padding: 0; display: grid; gap: .75rem; }
.setbar-key li { display: flex; gap: .7rem; font-size: .93rem; line-height: 1.55; }
.setbar-key .sw { flex: 0 0 auto; width: 11px; height: 11px; margin-top: .42rem; border-radius: 2px; print-color-adjust: exact; }
.sw-city   { background: var(--accent); }
.sw-flock  { background: #8a3a36; }
.sw-vendor { background: var(--bar-context); }

.share-line { margin-top: 1.75rem; }

/* ---------- reconciliation infographic (memo page) ---------- */

.recon { margin: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; background: var(--ink-2); }
.recon-title {
  background: var(--ink-3); border-bottom: 1px solid var(--line-soft);
  padding: .95rem 1.1rem .8rem;
}
.recon-title b { display: block; font-family: var(--serif); font-size: 1.12rem; color: #fff; line-height: 1.25; }
.recon-title span { display: block; margin-top: .3rem; font-size: .82rem; color: var(--text-dim); }
.recon-head { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--line-soft); }
.recon-head span {
  background: var(--ink-3); padding: .6rem 1.1rem; font-family: var(--mono);
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint);
}
.recon-head span:last-child { color: var(--accent-soft); }
.recon-row { border-top: 1px solid var(--line-soft); padding: .95rem 1.1rem; }
.recon-row:first-of-type { border-top: 0; }
.recon-row .topic {
  display: block; font-family: var(--mono); font-size: .66rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-faint); margin-bottom: .55rem;
}
.recon-pair { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: baseline; }
.recon-pair .says { color: var(--text-dim); font-size: .95rem; line-height: 1.45; max-width: none; }
.recon-pair .is   { color: #fff; font-weight: 600; font-size: .95rem; line-height: 1.45; max-width: none; }
.recon-pair .sep  { color: var(--accent); font-family: var(--mono); font-size: .95rem; }
.recon-foot {
  border-top: 1px solid var(--line-soft); background: var(--ink-3);
  padding: .7rem 1.1rem; font-size: .82rem; color: var(--text-dim);
  display: flex; flex-wrap: wrap; gap: .3rem 1rem; align-items: baseline; justify-content: space-between;
}
.recon-foot b { color: var(--accent-soft); font-family: var(--mono); font-size: .8rem; letter-spacing: .04em; }

@media (max-width: 640px) {
  .recon-head { display: none; }
  .recon-pair { grid-template-columns: 1fr; gap: .5rem; }
  .recon-pair .sep { display: none; }
  .recon-pair .says::before,
  .recon-pair .is::before {
    display: block; font-family: var(--mono); font-size: .64rem; letter-spacing: .12em;
    text-transform: uppercase; font-weight: 400; margin-bottom: .15rem;
  }
  .recon-pair .says::before { content: "Memo says"; color: var(--text-faint); }
  .recon-pair .is::before   { content: "Documents say"; color: var(--accent-soft); }
}

/* ---------- tables ---------- */

/* A table wider than the phone it is being read on.

   Most of these tables carry a sentence-length column, so on a 390px screen
   they genuinely need more width than they have and the row has to scroll.
   What was wrong was not the scrolling, it was that nothing admitted to it:
   the last column arrived cut off mid-word with no edge, no shadow and no
   hint, so a phone reader had no reason to think there was anything to the
   right of "The netw". Three things fix that, none of which change the table.

   1. .table-wrap, injected by script around the scroller, paints a fade over
      whichever edge still has content behind it. It has to be a separate box
      because a pseudo-element on the scroller scrolls away with the content.
   2. The caption is pinned to the left and held to the visible width. It was
      inheriting the table's min-width and being clipped with it, which lost
      the sourcing line — the one part of a table here that is never optional.
   3. The scroller becomes a focusable region, so arrow keys can move a table
      that a mouse wheel and a thumb could already move.

   Without script the table still scrolls by touch. It only loses the hint. */
.table-wrap { position: relative; margin: 1.6rem 0; }
.table-wrap::before,
.table-wrap::after {
  content: ""; position: absolute; top: 1px; bottom: 1px; z-index: 1;
  width: 2.25rem; pointer-events: none;
  opacity: 0; transition: opacity .18s ease;
}
.table-wrap::before {
  left: 1px; border-radius: 8px 0 0 8px;
  background: linear-gradient(to right, rgba(10, 17, 25, .92), rgba(10, 17, 25, 0));
}
.table-wrap::after {
  right: 1px; border-radius: 0 8px 8px 0;
  background: linear-gradient(to left, rgba(10, 17, 25, .92), rgba(10, 17, 25, 0));
}
.table-wrap.can-left::before { opacity: 1; }
.table-wrap.can-right::after { opacity: 1; }
@media print { .table-wrap::before, .table-wrap::after { display: none; } }

.table-scroll { overflow-x: auto; margin: 1.6rem 0; border: 1px solid var(--line); border-radius: 9px; }
.table-wrap .table-scroll { margin: 0; }
.table-scroll:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; }
table { border-collapse: collapse; width: 100%; font-size: .92rem; min-width: 560px; }
caption { text-align: left; font-size: .85rem; color: var(--text-faint); padding: .8rem 1rem; border-bottom: 1px solid var(--line-soft); }
/* --cap is the scroller's visible width, set by script. Falls back to the
   table's own width, which is what the caption used before. */
.table-scroll caption { position: sticky; left: 0; width: var(--cap, auto); box-sizing: border-box; }
th, td { padding: .68rem .9rem; text-align: left; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
thead th { background: var(--ink-2); color: #fff; font-family: var(--sans); font-size: .8rem; letter-spacing: .06em; text-transform: uppercase; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr.hl td { background: rgba(226,72,61,.08); }
td.num { font-family: var(--mono); font-size: .88rem; white-space: nowrap; }

/* 560px was one number for every table at every width. On a phone it was
   hiding 210-260px of every row — roughly the whole last column — when the
   same tables read fine narrower, because the only cell that needs the room
   is the prose one and prose wraps. Tightening the floor and the cell padding
   together brings most of these back inside the screen; the ones that still
   scroll now say so. */
@media (max-width: 640px) {
  table { min-width: 440px; font-size: .88rem; }
  th, td { padding: .6rem .65rem; }
  caption { padding: .7rem .8rem; }
}

/* ---------- citations ---------- */

.cite {
  font-family: var(--mono); font-size: .72em; vertical-align: super;
  text-decoration: none; color: var(--accent-soft); padding: 0 .06em;
  line-height: 0;
}
.cite:hover { color: #fff; text-decoration: underline; }

.sources { list-style: none; counter-reset: src; margin: 1.5rem 0 0; padding: 0; }
.sources li {
  counter-increment: src; position: relative; padding: .75rem 0 .75rem 3rem;
  border-bottom: 1px solid var(--line-soft); font-size: .93rem; line-height: 1.55;
}
.sources li::before {
  content: "[" counter(src) "]"; position: absolute; left: 0; top: .75rem;
  font-family: var(--mono); font-size: .8rem; color: var(--accent-soft);
}
.sources li:target { background: rgba(226,72,61,.09); border-radius: 6px; }
.sources .meta { display: block; color: var(--text-faint); font-size: .86rem; margin-top: .2rem; }

/* ---------- misc ---------- */

.prose { max-width: var(--measure); }
.prose ul, .prose ol { max-width: var(--measure); padding-left: 1.2rem; }
.prose li { margin-bottom: .5rem; }

.footnote { font-size: .85rem; color: var(--text-faint); }
blockquote { max-width: 74ch; }
blockquote p { max-width: none; }

/* A passage quoted verbatim from a city document, as distinct from the site's own
   prose around it. Same treatment the claim cards use. */
.docquote {
  margin: 0 0 1.1rem; padding-left: 1rem; border-left: 2px solid var(--line);
  font-family: var(--serif); font-size: 1.04rem; line-height: 1.55; color: var(--text);
}
.docquote p { margin: 0 0 .75rem; max-width: none; }
.docquote p:last-child { margin-bottom: 0; }
.mt1 { margin-top: 1.25rem; }

.cta-strip { background: var(--ink-2); }

.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; margin-top: 1.5rem; }
.card {
  background: var(--ink-2); border: 1px solid var(--line-soft); border-radius: 9px; padding: 1.25rem 1.35rem;
}
.card h3 { margin-top: 0; font-size: 1.08rem; }
.card p:last-child { margin-bottom: 0; }
.card p { max-width: none; }

.reveal { opacity: 0; transform: translateY(14px); transition: opacity .55s ease, transform .55s ease; }
.reveal.in { opacity: 1; transform: none; }

/* ---------- footer ---------- */

footer {
  background: #0a1119; border-top: 1px solid var(--line-soft);
  padding: 2.5rem 0 3rem; margin-top: 0;
}
.disclaimer { font-size: .84rem; line-height: 1.65; color: var(--text-faint); max-width: 86ch; }
.disclaimer strong { color: var(--text-dim); }

/* Heading anchor links. Injected by script onto every h2 and h3 that has an
   addressable target. Hidden until the heading is hovered or the link itself is
   focused, so it is available without being decoration the rest of the time.
   Clicking copies the full URL and leaves a brief confirmation. */
.anchor {
  font-family: var(--mono); font-weight: 400; font-size: .72em;
  color: var(--text-faint); text-decoration: none;
  opacity: 0; transition: opacity .13s ease, color .13s ease;
  padding: 0 .18em; border-radius: 4px; vertical-align: baseline;
}
h2:hover > .anchor, h3:hover > .anchor, summary:hover .anchor { opacity: 1; }
.anchor:hover { color: var(--accent-soft); }
.anchor:focus-visible { opacity: 1; outline: 2px solid var(--accent-soft); outline-offset: 2px; }
.anchor.copied { opacity: 1; color: var(--accent-soft); }
.anchor.copied::after {
  content: "link copied";
  margin-left: .5em; font-size: .78em; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-faint);
}

/* Touch devices have no hover, so the affordance would never appear. */
@media (hover: none) { .anchor { opacity: .45; } }

@media print { .anchor { display: none; } }

/* The front-page directory. It used to be five unlabeled buttons for seven
   pages, which told a newcomer nothing about what they were taking on and
   omitted the two newest pages entirely. Each entry now says what the page
   answers and roughly what it costs to read. */
.guide { list-style: none; counter-reset: guide; margin: 1.6rem 0 0; padding: 0; max-width: 82ch; }
.guide li {
  display: flex; align-items: baseline; gap: 1rem;
  border-top: 1px solid var(--line-soft);
}
.guide li:last-child { border-bottom: 1px solid var(--line-soft); }
.guide a {
  flex: 1 1 auto; display: block; padding: 1rem .4rem 1.05rem 0;
  text-decoration: none; color: inherit; border-radius: 7px;
}
.guide a:hover b { color: #fff; }
.guide a:hover span { color: var(--text-dim); }
.guide a:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; }
.guide b {
  display: block; font-family: var(--serif); font-size: 1.12rem; font-weight: 700;
  color: var(--text); margin-bottom: .25rem;
}
.guide b::after { content: " \2192"; color: var(--accent); font-family: var(--sans); }
.guide span { display: block; color: var(--text-faint); font-size: .92rem; line-height: 1.5; max-width: 62ch; }
.guide em {
  flex: 0 0 auto; align-self: center; font-style: normal;
  font-family: var(--mono); font-size: .68rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint);
  white-space: nowrap;
}
.guide em.now {
  color: var(--notice); border: 1px solid rgba(232,178,58,.4);
  border-radius: 999px; padding: .3rem .6rem;
}
@media (max-width: 560px) {
  .guide li { flex-wrap: wrap; gap: .3rem; }
  .guide a { padding-bottom: .5rem; }
  .guide em { margin-bottom: .9rem; }
}

/* Partner projects. These used to sit in the top nav, where three logos of
   different proportions fought the page links for the same row. Down here they
   read as what they are: related work, not navigation. The image is the link;
   main.js flips it to the text fallback if the file fails to load. */
.partners {
  display: flex; align-items: center; flex-wrap: wrap; gap: .8rem 1.6rem;
  margin: 1.9rem 0 0; padding-top: 1.6rem; border-top: 1px solid var(--line-soft);
}
.partners-label {
  font-family: var(--mono); font-size: .68rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-faint);
}
.partners ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; align-items: center; flex-wrap: wrap; gap: .5rem 1.4rem;
}
.partners a.logo-link {
  display: inline-flex; align-items: center; gap: 6px;
  padding: .3rem .1rem; border-radius: 6px;
  color: var(--text-dim); text-decoration: none; font-size: .88rem;
  opacity: .72; transition: opacity .15s ease, color .15s ease;
}
.partners a.logo-link:hover, .partners a.logo-link:focus-visible { opacity: 1; color: var(--text); }
.partners a.logo-link:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; }
.partners a.logo-link img { display: block; height: 21px; width: auto; max-width: 118px; }
.partners a.logo-link .fallback { display: none; }
.partners a.logo-link.noimg img { display: none; }
.partners a.logo-link.noimg .fallback { display: inline; }
.partners a.ext::after { content: " \2197"; font-size: .78em; opacity: .65; }

@media (max-width: 560px) {
  .partners { gap: .7rem 1.1rem; }
  .partners ul { gap: .5rem 1.1rem; }
}

/* Demand lines shared across this family of sites — keep wording in sync with flockmarinelli.com. */
.footer-demand {
  font-family: var(--serif); font-weight: 700; font-size: 1.05rem; max-width: none;
  color: var(--demand); letter-spacing: .5px; text-align: center; margin: 1.4rem 0 0;
}
.footer-demand + .footer-demand { margin-top: .4rem; }
.footer-demand a { color: inherit; text-decoration: none; }
.footer-demand a:hover { text-decoration: underline; }

.copy { font-size: .82rem; color: var(--text-faint); margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--line-soft); }

/* ---------- claims page: verdict chips and claim blocks ---------- */

.verdicts { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: .75rem; margin: 1.5rem 0 0; }
.verdicts div { background: var(--ink-2); border: 1px solid var(--line-soft); border-radius: 9px; padding: .85rem 1rem; }
.verdicts .v { font-family: var(--mono); font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; font-weight: 600; display: block; margin-bottom: .35rem; }
.verdicts p { margin: 0; font-size: .88rem; color: var(--text-dim); line-height: 1.5; }

.claim { background: var(--ink-2); border: 1px solid var(--line-soft); border-left: 3px solid var(--line); border-radius: 9px; padding: 1.25rem 1.35rem; margin: 0 0 .9rem; }
.claim-head { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-bottom: .8rem; }
.claim-head .no { font-family: var(--mono); font-size: .8rem; color: var(--text-faint); }
.claim blockquote { margin: 0 0 .85rem; padding-left: .95rem; border-left: 2px solid var(--line); font-family: var(--serif); font-size: 1.04rem; line-height: 1.55; color: var(--text); }
.claim p { margin: 0 0 .7rem; font-size: .96rem; color: var(--text-dim); }
.claim p:last-child { margin-bottom: 0; }
.claim strong { color: var(--text); }
.claim .against { margin-top: .85rem; padding-top: .75rem; border-top: 1px dashed var(--line); font-size: .9rem; }
.claim .against b { font-family: var(--mono); font-size: .7rem; letter-spacing: .09em; text-transform: uppercase; color: var(--text-faint); display: block; margin-bottom: .3rem; font-weight: 600; }

.chip { font-family: var(--mono); font-size: .67rem; letter-spacing: .1em; text-transform: uppercase; font-weight: 600; padding: .25rem .55rem; border-radius: 3px; white-space: nowrap; }
/* nowrap keeps a two-word verdict off two lines, but the long ones — "a
   statement of intent, not a control" — are wider than a 320px phone, and a
   chip that cannot wrap takes the whole page sideways with it. Below the width
   where that happens, let them wrap. */
@media (max-width: 400px) { .chip { white-space: normal; } }
.chip-ok      { background: rgba(95, 191, 143, .14); color: #7fd3a8; }
.chip-narrow  { background: rgba(232, 178, 58, .14); color: var(--verdict-narrow); }
.chip-bad     { background: rgba(226, 72, 61, .16); color: var(--accent-soft); }
.chip-unknown { background: rgba(147, 166, 186, .12); color: var(--text-dim); }

.claim-ok     { border-left-color: #5fbf8f; }
.claim-narrow { border-left-color: var(--verdict-narrow); }
.claim-bad    { border-left-color: var(--accent); }
.claim-unknown{ border-left-color: var(--text-faint); }

/* Bars inside a table row.

   Both of these tables are magnitude comparisons that were arriving as columns
   of digits, which is the slowest possible way to read "17 against 150". The
   bar is a second encoding of the number already in the row, so the table stays
   the citable source and the reader gets the shape for free. No script, no SVG,
   and it prints.

   Emphasis, not a value ramp. Coloring each bar darker-where-bigger would
   double-encode length as hue and, on the camera-count table, imply an order
   that four unrelated documents do not have. One accent bar carries the value
   the argument turns on, the rest are context.

   The --v percentage is data, not styling, which is why it is set inline: there
   is no way to express a per-row value in a stylesheet without a class per
   number. */
.barcell { width: 164px; min-width: 96px; padding-right: 1.1rem !important; vertical-align: middle; }
.bar {
  display: block;
  width: var(--v, 0%);
  height: 9px;
  min-width: 3px;
  border-radius: 0 4px 4px 0;   /* rounded at the data end, square at the baseline */
  background: var(--bar-context);
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}
.bar-key { background: var(--bar-key); }
@media (max-width: 620px) { .barcell { width: 84px; min-width: 64px; } }

.faceoff { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; margin: .9rem 0 0; }
.faceoff > div { background: var(--ink-3); border: 1px solid var(--line-soft); border-radius: 8px; padding: .9rem 1rem; }
.faceoff h4 { margin: 0 0 .5rem; font-family: var(--mono); font-size: .68rem; letter-spacing: .09em; text-transform: uppercase; color: var(--text-faint); font-weight: 600; }
.faceoff q { display: block; font-family: var(--serif); font-size: .97rem; line-height: 1.5; color: var(--text); }
@media (max-width: 620px) { .faceoff { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   Disclosure blocks

   Native <details>/<summary>, no library. The rule this page follows: the
   summary carries the finding, the body carries the proof. With every block
   closed the argument still reads end to end; opening one shows the documents
   behind that line. Everything below is presentation only, so the content
   stays reachable if the stylesheet never loads.
   --------------------------------------------------------------------------- */

details.dx > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: .75rem;
  border-radius: 6px;
  transition: color .15s ease;
}
details.dx > summary::-webkit-details-marker { display: none; }
details.dx > summary::after {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: .46rem;
  height: .46rem;
  margin-left: auto;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: translateY(-.12em) rotate(45deg);
  transition: transform .18s ease, border-color .18s ease;
}
details.dx[open] > summary::after { transform: translateY(.1em) rotate(-135deg); }
details.dx > summary:hover { color: var(--text); }
details.dx > summary:hover::after { border-color: var(--accent-soft); }
details.dx > summary:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; }
details.dx > summary > h3,
details.dx > summary > .label { margin: 0; }

/* Stacked disclosures inside a prose column: one per heading. */
.dx-row { border-top: 1px solid var(--line-soft); }
.dx-row + .dx-row { margin-top: 0; }
.dx-row > summary { padding: .9rem .15rem; }
.dx-row > summary > h3 { font-size: 1.04rem; line-height: 1.4; }
.dx-row[open] > summary > h3 { color: var(--accent-soft); }
.dx-row > *:not(summary):first-of-type { margin-top: 0; }
.dx-row > *:not(summary):last-child { margin-bottom: 1.3rem; }

/* Line by line: the whole claim opens. Closed, a claim is its verdict and the
   sentence it is a verdict on, which is the unit a reader scans. */
details.dx.dx-claim > summary {
  display: block;
  position: relative;
  padding-right: 1.9rem;
}
details.dx.dx-claim > summary::after {
  position: absolute;
  top: .5rem;
  right: .15rem;
  margin-left: 0;
  align-self: auto;
}
details.dx.dx-claim > summary .claim-head { margin-bottom: .75rem; }
details.dx.dx-claim > summary q {
  display: block;
  margin: 0;
  padding-left: .95rem;
  border-left: 2px solid var(--line);
  font-family: var(--serif);
  font-size: 1.04rem;
  line-height: 1.55;
  color: var(--text);
  quotes: none;
}
details.dx.dx-claim > summary q::before, details.dx.dx-claim > summary q::after { content: none; }
details.dx.dx-claim > summary:hover q { color: #fff; }
details.dx.dx-claim[open] > summary { margin-bottom: 1.05rem; }
details.dx.dx-claim[open] > summary q { border-left-color: var(--accent); }
details.dx.dx-claim > *:not(summary):last-child { margin-bottom: 0; }

/* A card that opens (the "cannot answer" grid). */
details.card.dx > summary > h3 { font-size: 1.08rem; }
details.card.dx[open] > summary { margin-bottom: .7rem; }

/* .note and .gap keep their own box; only the label becomes the handle. */
details.note.dx > summary,
details.gap.dx > summary { padding: 0; }
details.note.dx[open] > summary,
details.gap.dx[open] > summary { margin-bottom: .75rem; }

/* Open/close-all control. Injected by script, so it never appears without
   the behavior behind it. */
.dx-all {
  appearance: none;
  -webkit-appearance: none;
  display: inline-block;
  margin: 1.1rem 0 0;
  padding: .5rem .9rem;
  background: var(--ink-2);
  color: var(--text-dim);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.dx-all:hover { color: var(--text); border-color: var(--text-faint); }
.dx-all:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 2px; }

@media print {
  details.dx > summary::after { display: none; }
  details.dx > summary { cursor: auto; }
  .dx-all { display: none; }
}

/* ---------------------------------------------------------------------------
   Page density control

   Injected by script on pages carrying four or more disclosure blocks, so it
   never appears without the behavior behind it. It sticks under the header
   because a control that only exists at the top of a twenty-screen page is a
   control nobody reaches.
   --------------------------------------------------------------------------- */

.density {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: .7rem;
  flex-wrap: wrap;
  padding: .5rem max(1.25rem, calc((100% - var(--wrap)) / 2 + 1.25rem));
  background: rgba(15, 23, 33, .97);
  border-bottom: 1px solid var(--line-soft);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.density-label { color: var(--text-faint); font-weight: 600; }
.density-seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}
.density-btn {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  color: var(--text-dim);
  border: 0;
  padding: .4rem .85rem;
  font: inherit;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.density-btn + .density-btn { border-left: 1px solid var(--line); }
.density-btn:hover { color: var(--text); background: var(--ink-2); }
.density-btn[aria-pressed="true"] { background: var(--ink-3); color: var(--text); }
.density-btn:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: -2px; }
.density-count { color: var(--text-faint); margin-left: auto; text-transform: none; letter-spacing: .04em; }

@media (max-width: 640px) {
  .density { gap: .5rem; padding: .3rem 1rem; flex-wrap: nowrap; }
  .density-label { display: none; }
  .density-btn { padding: .32rem .7rem; }
  /* .62rem resolved to under 10px, which was the smallest text on the site and
     the only piece of it that reported a changing state. */
  .density-count { font-size: .7rem; text-align: right; line-height: 1.25; }
}

@media print { .density { display: none; } }

/* ---------------------------------------------------------------------------
   Touch targets

   Measured on a 390px viewport, every control in the page chrome came in under
   the 44px a thumb needs, and several under the 24px WCAG 2.2 asks for as a
   floor: the menu button that is the only navigation on a phone was 38x32, the
   carousel dots 23x23, the Brief/Full segments 28 tall, and the summary of a
   note or gap disclosure — which carries padding: 0 so the callout keeps its
   own box — was a 19px-tall strip of text.

   Scoped to a coarse pointer, so none of this moves on a mouse. Where growing
   a control would have pushed the layout around, it grows into padding it was
   already sitting inside rather than adding height to the page.
   --------------------------------------------------------------------------- */
@media (pointer: coarse) {
  .brand { padding: .55rem; }

  /* Below 560px the word "Menu" is hidden and only the bars are left, which
     took the button to 38px wide. It is the only navigation on a phone. */
  .nav-toggle { min-height: 44px; min-width: 44px; justify-content: center; padding-top: 0; padding-bottom: 0; }

  /* The dot is 11px of ink in a 23px box. Only the box grows. */
  .hero-dots { gap: 0; }
  .hero-dots button { padding: 16px 10px; }

  .density-btn { min-height: 40px; padding-top: 0; padding-bottom: 0; }
  .dx-all { min-height: 44px; padding-top: 0; padding-bottom: 0; }

  #site-menu a { padding-top: .75rem; padding-bottom: .75rem; }

  /* The note/gap handle. The negative margin gives the padding back to the
     callout, so the target doubles without the box growing to match. */
  details.note.dx > summary,
  details.gap.dx > summary { padding: .75rem 0; margin: -.75rem 0; }
  details.note.dx[open] > summary,
  details.gap.dx[open] > summary { margin-bottom: 0; }

  .dx-row > summary { padding-top: 1rem; padding-bottom: 1rem; }

  /* Same trick as the note/gap handle: the card already has the padding, the
     summary just was not claiming any of it. */
  details.card.dx > summary { padding: .5rem 0; margin: -.5rem 0; }
  details.card.dx[open] > summary { margin-bottom: .2rem; }

  /* A citation marker is 20x12 and sits in running text, where it cannot take
     real padding without opening up the line. The hit area is expanded off the
     box instead: taller, because that is the axis a thumb misses on, and only
     barely wider, because [3][10][11] run together and must stay separable. */
  .cite { position: relative; }
  .cite::after { content: ""; position: absolute; inset: -11px -2px; }

  .anchor { padding: .5rem .35rem; }

  /* Footer partner links: 21px logos in a 31px-tall link. */
  .partners a.logo-link { min-height: 44px; padding-left: .3rem; padding-right: .3rem; }

  html { -webkit-tap-highlight-color: rgba(226, 72, 61, .18); }
}

/* Phones: the amber notice and the watchdog line stacked to ~320px, so the
   headline started below the fold on a 812px-tall screen. Same words, tighter
   type and padding. */
@media (max-width: 560px) {
  .council-banner { padding: .6rem 1rem; font-size: .88rem; line-height: 1.4; }
  .council-banner strong { font-size: .76rem; }
  .watchdog-banner { padding: .4rem 1rem; font-size: .68rem; letter-spacing: .04em; line-height: 1.4; }
  .hero { padding-top: 2rem; }
}

/* Notched phones in landscape: keep text out from under the sensor housing. */
@supports (padding: max(0px)) {
  .wrap, .nav { padding-left: max(1.25rem, env(safe-area-inset-left)); padding-right: max(1.25rem, env(safe-area-inset-right)); }
}
