/* ------------------------------------------------------------------
   Battery Park Community Activism
   Type and nothing else: Bebas Neue capitals for display and figures,
   EB Garamond for reading. Paper and ink with one harbor-blue accent;
   orange only for what happened, red only for overrun figures.
   Light and dark follow the OS; the dark theme swaps paper and ink.
   No rules and no outlined boxes: surfaces step in tone, sections are
   separated by space or by a change of field.
   Radius: square buttons, 8px small controls, 12px filled surfaces.
   ------------------------------------------------------------------ */

@font-face {
  font-family: "Bebas Neue";
  src: url("../fonts/bebas-neue-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "EB Garamond";
  src: url("../fonts/ebgaramond-var.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "EB Garamond";
  src: url("../fonts/ebgaramond-var-italic.woff2") format("woff2");
  font-weight: 400 800;
  font-style: italic;
  font-display: swap;
}

:root {
  color-scheme: light dark;

  /* Paper and ink: one ground, one ink, one accent. Harbor blue is the accent
     (actions, links, and the ink of what was promised). Orange is the ink of
     what happened; red is reserved for overrun figures. */
  --page: #f0efeb;
  --surface: #e6e4de;
  --surface-2: #dedbd4;
  --surface-3: #d6d3ca;
  --ink: #15181c;
  --ink-2: #3a3f46;
  --ink-muted: #5c6168;
  --grid: #dcd9d1;
  --hairline: #cfcbc1;
  --accent: #165a9c;
  --accent-ink: #ffffff;
  --accent-soft: #dde6ef;
  /* Orange for type at reading sizes: the chart orange darkened until it
     reads at 4.5:1 on the page and on the first tone step. Display sizes
     keep the chart orange itself. */
  --ink-outcome: #a83f17;
  --bad: #b13333;
  --bad-soft: #f1e1dd;
  --good: #1d6b3a;
  --chart-blue: #2a78d6;
  --chart-orange: #d95a26;

  /* The inverted fields: ink ground, paper type. In the dark theme the same
     tokens resolve to a paper field with ink type. */
  --inverse: var(--ink);
  --on-inverse: var(--page);
  --bad-on-inverse: #f25c5c;
  /* The accent as it reads on the inverted field (the other theme's blue). */
  --accent-on-inverse: #6aade8;
  /* The ground a chart sits on. Charts are unboxed: on the page they take the
     page colour, inside a tone field they take the field's (see .section-field),
     so the halos lib/charts.js draws in var(--surface) match what is behind. */
  --chart-ground: var(--page);

  /* Data encodings for lib/map.js and lib/charts.js, not page colours. */
  --park: #2f6b3a;
  --park-soft: #e4f0e3;
  --water: #3d7eb5;
  --water-deep: #1a4a73;
  --sand: #efe4cc;
  --amber: #c47a12;
  --amber-soft: #f8edd8;
  --hue-northwest: #165a9c;
  --hue-south: #c45c26;
  --hue-wharf: #0e7c7b;
  --hue-fields: #2a7a3a;
  --hue-playscape: #c9a227;

  --display: "Bebas Neue", "Avenir Next Condensed", "Arial Narrow", sans-serif;
  --text: "EB Garamond", Garamond, "Iowan Old Style", Georgia, serif;

  /* Five steps, plus the title step every inner-page h1 uses. The home page
     adds its two poster sizes: the statement (display) and the figure.
     Every font-size on the site is one of these. EB Garamond's x-height is
     small, so the small step reads at 17px on a desktop (15.6px at 390) and
     the body step at 20px (17.2px at 390). */
  --step-small: clamp(0.9375rem, 0.9rem + 0.3vw, 1.0625rem);
  --step-body: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  --step-lead: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
  --step-head: clamp(2.5rem, 1.2rem + 5vw, 5.5rem);
  /* Above the head step at every width from 600px up (60px against 58px at
     768). On a phone it resolves to the head step (below), so the page's one
     figure at 34vw is a page's fifth size, not its sixth. */
  --step-title: clamp(2.75rem, 0.9rem + 6vw, 8.5rem);
  /* The hero blueprint's statement: its longer line reaches column 11. */
  --step-display: min(15vw, 14.375rem);
  /* The stats blueprint's figure, also the showcase specimens and the
     one-word button: the home page's poster size. */
  --step-figure: clamp(11.25rem, 23vw, 23.75rem);

  /* Older names, mapped onto the steps. */
  --fs-small: var(--step-small);
  --fs-body: var(--step-body);
  --fs-lede: var(--step-lead);
  --fs-h2: var(--step-head);
  --fs-figure: var(--step-head);
  --fs-h1: var(--step-title);

  /* One frame: the outer margin of the full-bleed home fields, the gutter of
     the 12-column grid, and the padding that lets a table's tone hang
     outside its text column. */
  --edge: 40px;
  --gutter: 24px;
  --cell-pad: 14px;

  /* Motion (tasteskill base.css). Curves: ease-out for anything under 600ms,
     expo for reveals of 800ms and longer, in-out for wipes and things that
     travel, soft for slow scale and drift on photographs. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.76, 0, 0.24, 1);
  --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);
  --ease-exit: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  --t-press: 140ms;
  --t-hover: 180ms;
  --t-ui: 240ms;
  --t-reveal: 800ms;
  --t-open: 1200ms;
  --stagger-line: 90ms;
  --stagger-item: 70ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --page: #15181c;
    --surface: #1f2328;
    --surface-2: #262b31;
    --surface-3: #2e343b;
    --ink: #f0efeb;
    --ink-2: #c9c7c0;
    --ink-muted: #9b998f;
    --grid: #2b3036;
    --hairline: #363c43;
    --accent: #6aade8;
    --accent-ink: #0b0b0b;
    --accent-soft: #16283d;
    /* Full saturation keeps the outcome ink a construction orange on the
       dark ground (about 7:1), clear of the muted rust family. */
    --ink-outcome: #ff7a3d;
    /* A loss reads as red, not salmon: 5.9:1 on the ground, 5.2:1 on the
       first tone step, 4.7:1 on the second. */
    --bad: #ff5c5c;
    --bad-soft: #35201f;
    --good: #7fce7f;
    --chart-blue: #3987e5;
    --chart-orange: #d95926;
    --bad-on-inverse: #b13333;
    --accent-on-inverse: #165a9c;
    --park: #7fce7f;
    --park-soft: #1a2e20;
    --water: #4a90c4;
    --water-deep: #8eb8dc;
    --sand: #2a2620;
    --amber: #e0a84a;
    --amber-soft: #3a2d14;
    --hue-northwest: #6aade8;
    --hue-south: #e07a45;
    --hue-wharf: #3db5b3;
    --hue-fields: #6dce7a;
    --hue-playscape: #e0c15a;
  }
}

@media (max-width: 959px) {
  :root { --edge: 32px; }
}
@media (max-width: 599px) {
  :root {
    --edge: 16px;
    --gutter: 16px;
    --cell-pad: 12px;
    /* On a phone the statement fills the width: the longer line, edge to edge. */
    --step-display: calc((100vw - 2rem) / 5.9);
    /* On a phone the title and the head step are one size (40px at 390), so
       an inner page holds five sizes with its figure at 34vw, and the home
       page's contact line adds none. */
    --step-title: var(--step-head);
  }
}
@media (max-width: 480px) {
  /* The stats blueprint's phone figure: four characters or more drop to 34vw. */
  :root { --step-figure: 34vw; }
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--text);
  font-size: var(--fs-body);
  line-height: 1.45;
  letter-spacing: 0;
  font-kerning: normal;
  /* Lining figures everywhere; proportional in prose, tabular in data (below). */
  font-variant-numeric: lining-nums proportional-nums;
  -webkit-font-smoothing: antialiased;
}

table,
.num,
.chart,
.pf-num,
.fr-num,
.stat-figure,
.specimen-figure,
.update-date,
.sparkline {
  font-variant-numeric: lining-nums tabular-nums;
}

.wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 1.25rem;
}
@media (max-width: 599px) {
  .wrap { padding: 0 1rem; }
}

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { text-decoration-thickness: 2px; }
/* Links answer the pointer: their hover colour and underline ease in over
   180ms where a real pointer hovers (touch fires hover on tap and would leave
   it stuck mid-fade). */
@media (hover: hover) and (pointer: fine) {
  a,
  .drawer-name {
    transition: color var(--t-hover) ease, background-color var(--t-hover) ease, text-decoration-color var(--t-hover) ease, text-decoration-thickness var(--t-hover) ease;
  }
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--accent-ink);
  padding: 0.5rem 1rem;
  z-index: 40;
}
.skip-link:focus { left: 0; }

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

.visually-hidden,
.finder.is-live .finder-building { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* A closed disclosure takes its content out of layout, not only out of paint
   (current Chrome lays hidden details content out without drawing it). */
details:not([open]) > :not(summary) { display: none; }

/* ---------- top edge (header): no bar, small text on the page ground ---------- */

.site-header {
  position: relative;
  z-index: 30;
}
.is-home .site-header {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 72px;
  padding-block: 14px;
}
.is-home .header-inner {
  max-width: none;
  padding-inline: 24px;
}
.brand {
  font-family: var(--text);
  font-weight: 600;
  font-size: var(--fs-small);
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.header-end {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}
/* Two renderings of the same links: a plain row on wide screens, a Menu
   disclosure below 960px. Only one is displayed at a time. */
.nav-bar {
  display: flex;
  gap: 1.4rem;
}
.nav-menu {
  display: none;
  position: relative;
  flex-shrink: 0;
}
.site-header nav a {
  color: var(--ink);
  text-decoration: none;
  font-size: var(--fs-small);
  font-weight: 500;
  padding: 0.5rem 0;
  white-space: nowrap;
}
.site-header nav a:hover {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
}
.site-header nav a[aria-current="page"] {
  text-decoration: underline 2px var(--accent);
  text-underline-offset: 0.35em;
}
.header-cta { font-size: var(--fs-small); }

@media (max-width: 959px) {
  .site-header .header-cta,
  .nav-bar { display: none; }
  .nav-menu { display: block; }
  .nav-summary {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    list-style: none;
    cursor: pointer;
    font-weight: 600;
    font-size: var(--fs-small);
    color: var(--ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.35em;
    white-space: nowrap;
  }
  .nav-summary::-webkit-details-marker { display: none; }
  .nav-menu nav {
    position: absolute;
    right: 0;
    top: calc(100% + 0.25rem);
    min-width: 14rem;
    background: var(--surface);
    border-radius: 12px;
    padding: 0.4rem;
    box-shadow: 0 12px 32px color-mix(in srgb, var(--ink) 16%, transparent); /* taste-skill-ignore: the open menu floats */
  }
  /* The accordion recipe: the open panel is one grid row that grows from
     0fr to 1fr (the opening move is in the motion section). The list keeps
     4px of room inside its clip for the links' focus rings. */
  .nav-menu[open] nav { display: grid; grid-template-rows: 1fr; }
  .nav-menu-list {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    padding: 4px;
    margin: -4px;
  }
  .nav-menu nav a {
    padding: 0.75rem 0.85rem;
    border-radius: 8px;
  }
  .nav-menu nav a:hover { background: var(--accent-soft); text-decoration: none; }
  .nav-menu nav a[aria-current="page"] {
    background: var(--accent-soft);
    color: var(--accent);
    text-decoration: none;
  }
}
@media (max-width: 599px) {
  .is-home .header-inner { padding-inline: 16px; }
}

/* ---------- type ---------- */

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 0.85;
  margin: 0 0 0.35em;
  text-wrap: balance;
  hyphens: none;
  overflow-wrap: break-word;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); margin-top: 0; }
h3 { font-size: var(--fs-lede); line-height: 0.95; letter-spacing: 0; margin-bottom: 0.4em; }
/* Tracking tightens as display type grows against the screen: on a phone the
   head and title steps are about 10vw, halfway to the 15vw where the system
   reaches -0.06em. */
@media (max-width: 599px) {
  h1, h2 { letter-spacing: -0.04em; }
}

p { margin: 0 0 1em; }
.lede {
  font-size: var(--fs-lede);
  line-height: 1.35;
  color: var(--ink);
  max-width: 58ch;
}
.lede-note {
  font-size: var(--fs-body);
  max-width: 62ch;
}
.prose { max-width: 68ch; }
.prose h2 { margin-top: 5rem; }
.prose h2:first-child { margin-top: 0; }
.prose ul { padding-left: 1.2rem; }
.prose li { margin-bottom: 0.4em; }

/* The two inks of the charts, used as type wherever a promise is set against
   an outcome: blue for what was promised, orange for what happened. */
.ink-promise { color: var(--accent); }
.ink-outcome { color: var(--ink-outcome); }
.is-bad { color: var(--bad); }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-family: var(--text);
  font-weight: 600;
  font-size: var(--fs-body);
  line-height: 1.2;
  padding: 0.6rem 1.25rem;
  border-radius: 0;
  text-decoration: none;
  white-space: nowrap;
  transition: transform var(--t-press) var(--ease-out), background-color var(--t-hover) ease, color var(--t-hover) ease;
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 84%, var(--ink)); }

/* ---------- home: the statement (hero blueprint "Stacked name, two inks") ---------- */

.home-hero {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
  padding: 14svh var(--edge) 40px;
  background: var(--page);
}
.statement {
  font-size: var(--step-display);
  line-height: 0.82;
  letter-spacing: -0.04em;
  margin: 0 0 2rem -0.03em;
  text-wrap: wrap;
}
.statement span { display: block; }
.statement .ink-outcome { color: var(--chart-orange); }
.hero-foot {
  margin-top: auto;
  align-self: flex-end;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1.25rem;
  text-align: right;
}
.hero-support {
  margin: 0;
  max-width: 30ch;
  font-size: var(--fs-body);
  color: var(--ink);
}
.hero-action { display: none; }

@media (max-width: 959px) {
  .hero-action { display: inline-flex; }
}
/* From 960px to 1099px the name and the six links at the small step leave
   no room for the button beside them (it needs about 1030px), so on the home
   page it moves down into the first screen's foot, as on tablets. */
@media (min-width: 960px) and (max-width: 1099px) {
  .site-header .header-cta { display: none; }
  .hero-action { display: inline-flex; }
}
@media (max-width: 599px) {
  .home-hero { padding: 18svh var(--edge) 24px; }
  .statement { margin: 0 0 1.5rem; }
  .hero-foot {
    align-self: stretch;
    align-items: flex-start;
    text-align: left;
  }
  .hero-support { max-width: none; }
  .hero-action { align-self: stretch; }
}
/* On a phone the field is as tall as its content: statement, sentence, button. */
@media (max-width: 480px) {
  .home-hero { min-height: 0; padding: 18svh var(--edge) 32px; }
  .statement { margin: 0 0 48px; }
  .hero-foot { margin-top: 0; gap: 24px; }
}

/* ---------- home: one figure owns the screen (stats blueprint), the inverted field ---------- */

.stat-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  column-gap: var(--gutter);
  min-height: 90svh;
  padding: 9svh var(--edge) 40px;
  background: var(--inverse);
  color: var(--on-inverse);
}
.stat-claim {
  grid-column: 1 / -1;
  grid-row: 1;
  font-size: var(--fs-h2);
  margin: 0 0 22svh;
}
.stat-body {
  grid-column: 1;
  grid-row: 3;
  align-self: end;
}
.stat-figure {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--step-figure);
  line-height: 0.8;
  letter-spacing: -0.04em;
  margin: 0 0 0 -0.02em;
  color: var(--bad-on-inverse);
  white-space: nowrap;
}
.stat-caption {
  font-size: var(--fs-body);
  max-width: 42ch;
  margin: 1.25rem 0 0;
}
.stat-source {
  grid-column: 2;
  grid-row: 3;
  align-self: end;
  justify-self: end;
  max-width: 34ch;
  margin: 0;
  font-size: var(--fs-small);
  text-align: right;
}
@media (max-width: 959px) {
  .stat-field { min-height: 80svh; }
}
@media (max-width: 719px) {
  .stat-field {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr auto auto;
  }
  .stat-source {
    grid-column: 1;
    grid-row: 4;
    justify-self: start;
    max-width: none;
    text-align: left;
    margin-top: 2rem;
  }
}
@media (max-width: 599px) {
  .stat-field { padding: 56px var(--edge) 32px; }
  .stat-claim { margin-bottom: 16svh; }
  .stat-figure { margin-left: 0; }
  .stat-caption { max-width: 80%; margin-top: 1rem; }
}

/* ---------- home: the three headline figures ---------- */

.figure-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem var(--gutter);
  margin: 0 0 2rem;
}
.fr-num {
  font-family: var(--display);
  font-size: var(--fs-lede);
  line-height: 1;
  text-transform: uppercase;
  margin: 0 0 0.35rem;
}
.fr-num.is-bad { color: var(--bad); }
.fr-label {
  font-size: var(--fs-small);
  color: var(--ink-2);
  max-width: 34ch;
  margin: 0;
}
@media (max-width: 599px) {
  .figure-row { grid-template-columns: 1fr; }
  .fr-label { max-width: none; }
}

/* ---------- home: the ledger (proof blueprint "Recognition as a table") ---------- */

.ledger {
  padding: clamp(4.5rem, 9vw, 8rem) var(--edge) clamp(3.5rem, 6vw, 5.5rem);
}
.ledger-head {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 1.5rem;
  align-items: end;
  margin-bottom: 3.5rem;
}
/* Two lines, the second set in two columns from the first. */
.ledger-title {
  grid-column: 1 / 8;
  display: grid;
  grid-template-columns: subgrid;
  margin: 0;
}
.ledger-title span { grid-column: 1 / -1; }
.ledger-title span + span { grid-column: 3 / -1; }
.ledger-note {
  grid-column: 9 / 13;
  margin: 0;
  max-width: 46ch;
}
.ledger .figure-row { margin-bottom: 4.5rem; }

/* No lines: every second row carries the first tone step, and the tone hangs
   outside the text column so the figures stay on the grid. */
.ledger-table {
  width: calc(100% + 2 * var(--cell-pad));
  margin: 0 calc(-1 * var(--cell-pad));
  table-layout: fixed;
  font-size: var(--fs-body);
  line-height: 1.35;
}
.ledger-table .c-year { width: 16.6%; }
.ledger-table .c-project { width: 33.2%; }
.ledger-table .c-cost { width: 33.2%; }
.ledger-table th,
.ledger-table td {
  padding: 14px var(--cell-pad);
  font-weight: 400;
  text-align: left;
  vertical-align: baseline;
  color: var(--ink);
}
.ledger-table tbody tr:nth-child(even) { background: var(--surface); }
/* One blank row between year groups. */
.ledger-table tbody + tbody tr:first-child > * { padding-top: calc(14px + 1.5em); }
.ledger-table .ledger-slip { text-align: right; }
.ledger-to { color: var(--ink-2); }

.ledger-chart {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: end;
  margin-top: 4.5rem;
}
.ledger-chart .chart-block { grid-column: 1 / 9; margin: 0; }
.ledger-chart .chart-caption { grid-column: 10 / 13; margin: 0; }
/* The schedule, beneath the cost chart: its head and sentence at the right,
   level with the chart's top (the cost chart's note above covers both). */
.ledger-chart-slip { align-items: start; margin-top: 5rem; }
.ledger-chart-slip .chart-block { grid-row: 1; }
.ledger-chart-head { grid-column: 10 / 13; grid-row: 1; }
.ledger-chart-head h3 { margin: 0 0 0.6rem; }
.ledger-chart-head p { margin: 0; max-width: 34ch; }

@media (max-width: 959px) {
  .ledger-title { grid-column: 1 / -1; }
  .ledger-title span + span { grid-column: 2 / -1; }
  /* Full width under the title, at a measure that reaches across it. */
  .ledger-note { grid-column: 1 / -1; max-width: 64ch; }
  .ledger-table .c-year { width: 11%; }
  .ledger-table .c-project { width: 43%; }
  .ledger-table .c-cost { width: 27%; }
  .ledger-chart { display: block; }
  .ledger-chart .chart-caption { margin-top: 0.75rem; }
  .ledger-chart-slip { margin-top: 3.5rem; }
  .ledger-chart-head { margin-bottom: 1.25rem; }
}
/* On a phone each row is a two-line block: the project, then its figures. The
   year stands once above its group. */
@media (max-width: 599px) {
  .ledger-table,
  .ledger-table tbody { display: block; }
  .ledger-table colgroup { display: none; }
  .ledger-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1rem;
    padding: 12px var(--cell-pad);
  }
  .ledger-table th,
  .ledger-table td { padding: 0; }
  .ledger-table .ledger-year {
    grid-column: 1 / -1;
    font-family: var(--display);
    font-size: var(--fs-lede);
    line-height: 1;
  }
  .ledger-table tr:first-child .ledger-year { margin-bottom: 10px; }
  .ledger-table .ledger-name { grid-column: 1 / -1; }
  .ledger-table .ledger-cost { grid-column: 1; }
  .ledger-table .ledger-slip { grid-column: 2; }
  .ledger-table tbody + tbody tr:first-child { padding-top: calc(12px + 1.5em); }
  .ledger-table tbody + tbody tr:first-child > * { padding-top: 0; }
}

/* ---------- home: who pays (intro blueprint "Lead line over four columns") ---------- */

.intro {
  padding: clamp(3.5rem, 6vw, 6rem) var(--edge) clamp(4.5rem, 8vw, 7rem);
}
.intro-lead {
  font-size: var(--fs-lede);
  line-height: 1.2;
  margin: 0 0 4.5rem;
}
.intro-cols {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}
.intro-cols p {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.45;
  color: var(--ink-2);
}
.intro-cols strong { color: var(--ink); font-weight: 700; }
@media (max-width: 959px) {
  .intro-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 20px; row-gap: 40px; }
}
@media (max-width: 599px) {
  .intro-lead { margin-bottom: 2.5rem; }
  .intro-cols { grid-template-columns: minmax(0, 1fr); row-gap: 32px; }
}

/* ---------- line-ups at one type size (list blueprint) ---------- */

.lineup {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  margin: 0;
}
.lineup th,
.lineup td {
  padding: 0;
  font-weight: 400;
  text-align: left;
  color: var(--ink);
}

/* Home: the projects, on the first tone step, edge to edge. */
.lineup-band {
  background: var(--surface);
  padding: 72px var(--edge) 96px;
}
.lineup-title {
  font-family: var(--text);
  font-size: var(--fs-lede);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent);
  margin: 0 0 20px;
}
.lineup-projects {
  font-size: var(--fs-lede);
  line-height: 1.5;
}
/* The name at 0, the status at a third, as the blueprint sets them; the
   status column takes the room the two short figure columns do not need,
   so the longest status ("Declared complete by the BPCA, September 24,
   2026") holds one line from about 1380px up. */
.lineup-projects .c-name { width: 33.3%; }
.lineup-projects .c-status { width: 43.3%; }
.lineup-projects .c-estimate { width: 11.7%; }
.lineup-projects th,
.lineup-projects td {
  vertical-align: baseline;
  padding-right: var(--gutter);
}
.lineup-projects td:last-child { padding-right: 0; text-align: right; }
.lineup-projects a {
  color: var(--ink);
  text-decoration-color: color-mix(in srgb, var(--ink) 35%, transparent);
  text-decoration-thickness: 1px;
}
.lineup-projects a:hover,
.lineup-projects tr.is-hot a {
  color: var(--accent);
  text-decoration-color: currentColor;
}
@media (max-width: 959px) {
  .lineup-projects,
  .lineup-projects tbody { display: block; }
  .lineup-projects colgroup { display: none; }
  .lineup-projects tr {
    display: grid;
    grid-template-columns: auto auto minmax(0, 1fr);
    column-gap: 0.75rem;
    margin: 0 0 18px;
  }
  .lineup-projects th { grid-column: 1 / -1; padding-right: 0; }
  .lineup-projects td {
    font-size: var(--fs-small);
    line-height: 1.45;
    color: var(--ink-2);
    padding-right: 0;
  }
}
@media (max-width: 599px) {
  .lineup-band { padding: 56px var(--edge) 64px; }
}

/* Get involved: the venues, where | when | how. */
.lineup-venues {
  font-size: var(--fs-body);
  line-height: 1.45;
}
.lineup-venues thead th {
  color: var(--accent);
  padding: 0 var(--gutter) 1rem 0;
  vertical-align: bottom;
}
.lineup-venues tbody th,
.lineup-venues td {
  padding: 0 var(--gutter) 2.25rem 0;
  vertical-align: top;
}
.lineup-venues td:last-child,
.lineup-venues thead th:last-child { padding-right: 0; }
.lineup-name { display: block; }
.lineup-desc { display: block; margin-top: 0.4em; color: var(--ink-2); }
.lineup-link { display: block; margin-top: 0.5em; }
@media (max-width: 759px) {
  .lineup-venues,
  .lineup-venues tbody,
  .lineup-venues tr,
  .lineup-venues tbody th,
  .lineup-venues td { display: block; }
  .lineup-venues thead { display: none; }
  .lineup-venues tr { margin: 0 0 2.25rem; }
  .lineup-venues tbody th,
  .lineup-venues td { padding: 0 0 0.85rem; }
  .lineup-venues td::before {
    content: attr(data-label);
    display: block;
    color: var(--accent);
  }
}

/* ---------- home: the biggest jump (showcase blueprint "Two giant words compared") ---------- */

/* Redrawn in Phase 7 at the owner's request. The blueprint had the section's
   bottom edge cut both figures at about 60% of their height; visitors read
   the cut as a rendering fault. The figures now stand whole, side by side on
   one baseline, and the section is as tall as its content. */
.showcase {
  padding: clamp(4.5rem, 9vw, 8rem) var(--edge);
}
.showcase-top {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 1.25rem;
  align-items: start;
}
.showcase-top h2 { grid-column: 1 / 7; margin: 0; }
.showcase-top p { grid-column: 7 / 13; margin: 0; max-width: 60ch; }
/* The two figures share one baseline: their feet line up even if one
   caption takes a second line. */
.specimens {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: end;
  margin-top: 12vh;
}
.specimen { grid-column: span 6; margin: 0; min-width: 0; }
.specimen figcaption { font-size: var(--fs-body); margin: 0 0 0.75rem; }
/* Each figure's mask (its line rises from behind it) is the figure's own
   0.8em line box, opened 0.15em above it and 0.08em below it. Bebas Neue's
   dollar sign runs 0.045em above that line box and its comma 0.02em below
   it, so at rest the mask clips nothing. The space below is taken back
   with a negative margin, so the mask adds no height of its own. */
.specimen-mask {
  font-size: var(--step-figure);
  padding: 0.15em 0 0.08em;
  margin-bottom: -0.08em;
  overflow: clip;
}
.specimen-figure {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1em;
  line-height: 0.8;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  margin: 0 0 0 -0.02em;
}
.specimen-figure.ink-outcome { color: var(--chart-orange); }
/* Below the desktop grid the two figures stack, each whole in its own band
   from edge to edge, the second in the inverse colours of the first. */
@media (max-width: 959px) {
  .showcase-top { display: block; }
  .showcase-top h2 { margin-bottom: 1.25rem; }
  .specimens { display: block; margin-top: 4.5rem; }
  .specimen + .specimen { margin-top: 2.5rem; }
  /* With the figures smaller, each name reads at the lead step. */
  .specimen figcaption { font-size: var(--fs-lede); line-height: 1.2; }
  .specimen-band {
    padding: 28px var(--edge);
    margin-inline: calc(-1 * var(--edge));
    background: var(--surface);
  }
  .specimen-outcome .specimen-band { background: var(--inverse); }
}

/* ---------- home: one word is the button (cta blueprint) ---------- */

/* The section holds the word's whole glyph box (it runs 0.3em below the
   baseline), so the space under the band belongs to this section. The word's
   size is the band's content width over 2.045 (below); here the band is the
   viewport's width less its two margins. */
.cta { padding-bottom: max(0px, calc(0.3 * (100vw - 2 * var(--edge)) / 2.045 - 24px)); }
.cta-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(2rem, 1fr) auto;
  min-height: 60svh;
  padding: 40px var(--edge) 0;
  background: var(--accent);
  color: var(--accent-ink);
  text-decoration: none;
  /* The word measures itself against the band's content box (cqi). */
  container-type: inline-size;
}
.cta-sentence {
  grid-column: 1;
  grid-row: 1;
  max-width: 34ch;
  font-size: var(--fs-body);
  line-height: 1.35;
}
.cta-arrow {
  grid-column: 2;
  grid-row: 1;
  width: 48px;
  height: 48px;
  margin-left: var(--gutter);
}
/* The one word spans the band's content width on one line, the home page's
   seventh size. "ATTEND" in Bebas at -0.04em inks 2.045em from the A's foot
   to the D's bowl, with 0.012em of side bearing before the A, so the size is
   the content width over 2.045 and the word steps left by that bearing: the
   ink meets both content edges (about 46vw at 1440, 45vw at 768 and 390). */
.cta-word {
  grid-column: 1 / -1;
  grid-row: 3;
  display: block;
  font-family: var(--display);
  font-size: calc((100vw - 2 * var(--edge)) / 2.045);
  font-size: clamp(6rem, 100cqi / 2.045, 100rem);
  white-space: nowrap;
  line-height: 0.8;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  /* The baseline sits 24px above the band's bottom edge. */
  margin: 0 0 calc(24px - 0.1em) -0.012em;
}
/* Hover and focus swap the field and the word (over 180ms under a pointer,
   with the other links). */
.cta-band:hover,
.cta-band:focus-visible {
  background: var(--accent-ink);
  color: var(--accent);
}
@media (max-width: 599px) {
  .cta-band { min-height: 46svh; padding-top: 20px; }
  .cta-arrow { width: 32px; height: 32px; }
}

/* ---------- home: latest updates ---------- */

.home-updates {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  padding: clamp(2.5rem, 4vw, 3.5rem) var(--edge) clamp(4.5rem, 9vw, 8rem);
}
.home-updates-head { grid-column: 1 / 5; }
.home-updates-head p { max-width: 34ch; }
.home-updates .update-list { grid-column: 6 / 13; }
@media (max-width: 959px) {
  .home-updates { display: block; }
  .home-updates-head { margin-bottom: 2.5rem; }
}

/* ---------- home: drawn, then built (the promise beside the outcome) ---------- */

.home-pair {
  padding: clamp(4.5rem, 9vw, 8rem) var(--edge) clamp(4rem, 7vw, 6rem);
}
.home-pair-head {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: end;
  margin-bottom: 3rem;
}
.home-pair-head h2 { grid-column: 1 / 7; margin: 0; }
.home-pair-head p { grid-column: 7 / 12; margin: 0; max-width: 46ch; }
@media (max-width: 959px) {
  .home-pair-head { display: block; margin-bottom: 2.5rem; }
  .home-pair-head h2 { margin-bottom: 1.25rem; }
}

/* ---------- home: the intro's flood picture beside its four paragraphs ---------- */

@media (min-width: 960px) {
  .intro-body {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gutter);
    align-items: start;
  }
  .intro-body > .picture { grid-column: 1 / 7; }
  .intro-body > .intro-cols {
    grid-column: 7 / 13;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 2.5rem;
  }
}
@media (max-width: 959px) {
  .intro-body > .intro-cols { margin-top: 2.5rem; }
}

/* ---------- home: the landfill, edge to edge between two type sections ---------- */

.home-band .picture figcaption {
  max-width: none;
  padding-inline: var(--edge);
}
/* On a phone the band re-crops to a portrait on its focus point. */
@media (max-width: 599px) {
  .home-band .picture img {
    aspect-ratio: 4 / 5;
    object-fit: cover;
    object-position: var(--focus, 50% 50%);
  }
}

/* ---------- home: Albany Street, beside the call to attend ---------- */

/* The large picture holds columns 1 to 7 at full height; the heading and
   its sentence sit top right, the second picture under them, its foot on
   the large one's. */
.home-now {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-template-rows: auto 1fr;
  column-gap: var(--gutter);
  row-gap: 2.5rem;
  padding: 0 var(--edge) clamp(4.5rem, 8vw, 7rem);
}
.home-now-head { grid-column: 8 / 13; grid-row: 1; }
.home-now-head h2 { margin: 0 0 1.25rem; }
.home-now-head p { margin: 0; max-width: 40ch; }
.home-now .now-main { grid-column: 1 / 8; grid-row: 1 / 3; }
.home-now .now-side { grid-column: 8 / 13; grid-row: 2; align-self: end; }
@media (max-width: 959px) {
  .home-now { display: block; }
  .home-now-head { margin-bottom: 2.5rem; }
  .home-now .now-side { margin-top: 2.25rem; }
}

/* ---------- home: beyond the ledger (the impacts, the case files, the archive) ---------- */

/* A figure-led line-up on the first tone step, edge to edge, in the manner
   of the projects line-up: three fixed column starts (0, a third, two
   thirds) and nothing between the rows but space. Each row leads with its
   page's own first-screen figure, in that page's ink, at the head step; then
   the page's name in the display face at the lead step, a link with no
   underline at rest; then one sentence at the body step. The rows arrive one
   after another. Below 960px the name sits over its sentence beside the
   figure; on a phone the figure stands above its name. */
.steer {
  background: var(--surface);
  padding: 72px var(--edge) 96px;
}
.steer .lineup-title { margin-bottom: 48px; }
.steer-list { list-style: none; margin: 0; padding: 0; }
.steer-list > li {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
  margin: 0 0 3rem;
}
.steer-list > li:last-child { margin-bottom: 0; }
/* One link holds the figure and the name. It is laid on the row's own
   columns (a subgrid), so both keep their places and the whole of both
   answers the pointer and the keyboard; the sentence stays plain text. */
.steer-link {
  grid-column: 1 / 9;
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  grid-template-columns: subgrid;
  column-gap: var(--gutter);
  align-items: start;
  color: var(--ink);
  text-decoration: none;
}
.steer-figure {
  grid-column: 1 / 5;
  display: block;
  margin: 0;
  font-family: var(--display);
  font-size: var(--fs-h2);
  font-weight: 400;
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: lining-nums tabular-nums;
}
.steer-figure.ink-outcome { color: var(--chart-orange); }
.steer-figure.is-bad { color: var(--bad); }
.steer-name { grid-column: 5 / 9; margin: 0; padding-right: var(--gutter); }
.steer-text { grid-column: 9 / 13; grid-row: 1; margin: 0; }
/* No underline at rest. Under the pointer and with keyboard focus the name
   takes the accent and an underline, the figure an underline in its own ink
   (its colour is its meaning), and focus rings both in the accent. */
.steer-link:hover .steer-name,
.steer-link:focus-visible .steer-name {
  color: var(--accent);
  text-decoration-line: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.12em;
}
.steer-link:hover .steer-figure,
.steer-link:focus-visible .steer-figure {
  text-decoration-line: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 0.06em;
}
.steer-link:focus-visible { outline-offset: 8px; }
@media (hover: hover) and (pointer: fine) {
  .steer-name,
  .steer-figure { transition: color var(--t-hover) ease, text-decoration-color var(--t-hover) ease; }
}
.steer-all { margin: 3.5rem 0 0; font-size: var(--fs-lede); }
@media (max-width: 959px) {
  .steer-list > li { grid-template-rows: auto 1fr; }
  .steer-link {
    grid-column: 1 / -1;
    grid-row: 1 / 3;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    grid-template-columns: subgrid;
    grid-template-rows: subgrid;
  }
  .steer-figure { grid-column: 1 / 6; grid-row: 1 / 3; }
  .steer-name { grid-column: 6 / 13; grid-row: 1; margin-bottom: 0.5rem; padding-right: 0; }
  .steer-text { grid-column: 6 / 13; grid-row: 2; }
}
@media (max-width: 599px) {
  .steer { padding: 56px var(--edge) 64px; }
  .steer .lineup-title { margin-bottom: 32px; }
  .steer-list > li { display: block; margin-bottom: 2.25rem; }
  .steer-link { display: block; }
  .steer-figure { margin-bottom: 0.5rem; }
  .steer-name { margin-bottom: 0.5rem; }
}

/* ---------- pictures ---------- */

/* One treatment for every picture on the site: full colour, square corners,
   no border, no shadow, nothing laid over it. The caption sits beneath at the
   small step: plain ink when a picture stands alone, the two inks where a
   before stands beside an after (the promise ink under the first, the outcome
   ink under the second). Credits are in the footer. */
.picture { margin: 0; min-width: 0; }
.picture img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--surface);
}
/* The frame clips the image, so its entrance (a shutter opening, a settle
   from a slight scale) and the landfill's drift move inside its own box. */
.picture-frame { overflow: clip; }
.picture figcaption {
  margin: 0.65rem 0 0;
  max-width: 60ch;
  font-size: var(--fs-small);
  line-height: 1.4;
  color: var(--ink);
}
.picture.promise figcaption { color: var(--accent); }
.picture.outcome figcaption { color: var(--ink-outcome); }
.picture figcaption a { color: inherit; }

/* Groups crop to one shared ratio (--ratio), each picture on its own focus
   point (--focus, from its entry in pictures.json). Cropping only. */
.pics-pair .picture img,
.pics-mosaic .picture img {
  aspect-ratio: var(--ratio);
  object-fit: cover;
  object-position: var(--focus, 50% 50%);
}

/* Two across at one ratio, 3:2 unless the pair sets its own. */
.pics-pair {
  --ratio: 3 / 2;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}
.pics-pair-43 { --ratio: 4 / 3; }
.pics-pair-169 { --ratio: 16 / 9; }
.pics-pair-11 { --ratio: 1 / 1; }
.pics-pair-45 { --ratio: 4 / 5; }

/* Promised versus delivered: a promise and an outcome head the two columns,
   cropped to one ratio so the two headings stay level. */
.pvd .picture { margin-bottom: 2rem; }
.pvd .picture img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: var(--focus, 50% 50%);
}

/* Two uneven: seven columns and five at their own ratios, their feet on one
   line. The flipped form puts the narrow one first. */
.pics-duo {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: end;
}
.pics-duo > :first-child { grid-column: 1 / 8; }
.pics-duo > :last-child { grid-column: 8 / 13; }
.pics-duo-flip > :first-child { grid-column: 1 / 6; }
.pics-duo-flip > :last-child { grid-column: 6 / 13; }

/* Four at one ratio: seven columns and five, then five and seven, the
   right-hand picture of each row set lower than its neighbour. */
.pics-mosaic {
  --ratio: 3 / 2;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 4rem;
  align-items: start;
}
.pics-mosaic > :nth-child(1) { grid-column: 1 / 8; }
.pics-mosaic > :nth-child(2) { grid-column: 8 / 13; margin-top: 8rem; }
.pics-mosaic > :nth-child(3) { grid-column: 1 / 6; }
.pics-mosaic > :nth-child(4) { grid-column: 6 / 13; margin-top: 8rem; }

/* Text and its picture side by side, the text first in the source: the text
   in columns 1 to 6, the picture in 8 to 12. The flipped form shows the
   picture at the left, in 1 to 6, and the text in 8 to 12. */
.pics-aside {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}
.pics-aside > :first-child { grid-column: 1 / 7; }
.pics-aside > :last-child { grid-column: 8 / 13; }
.pics-aside-flip > :first-child { grid-column: 8 / 13; grid-row: 1; }
.pics-aside-flip > :last-child { grid-column: 1 / 7; grid-row: 1; }
.pics-aside > * > :last-child { margin-bottom: 0; }
/* A section head beside its picture: the heading runs the full width (so it
   keeps to two lines), the sentence and the picture share the row under it. */
@media (min-width: 900px) {
  .pics-aside:not(.pics-aside-flip) > .section-head:first-child {
    grid-column: 1 / -1;
    grid-row: 1 / span 2;
    display: grid;
    grid-template-columns: subgrid;
    grid-template-rows: subgrid;
    align-items: start;
  }
  .pics-aside:not(.pics-aside-flip) > .section-head:first-child > h2 { grid-column: 1 / -1; grid-row: 1; }
  .pics-aside:not(.pics-aside-flip) > .section-head:first-child > :not(h2) { grid-column: 1 / 7; grid-row: 2; }
  .pics-aside:not(.pics-aside-flip) > .section-head:first-child + .picture { grid-column: 8 / 13; grid-row: 2; }
}
/* Beside a long list the picture holds in view while the list scrolls. */
.pics-aside-held > .picture { position: sticky; top: 2rem; }
/* A second wrap inside a section, holding the section's pictures. */
.section-pics { margin-top: 3rem; }

/* In a split section a picture can stand in the head's columns, under the
   heading, beside the list or prose it belongs to. */
.split > .section-head .picture { margin-top: 2.5rem; }

/* Spacing: a group sits close under its section head and three lines'
   distance from anything else. */
* + .pics-pair,
* + .pics-duo,
* + .pics-mosaic,
.pics-pair + *,
.pics-duo + *,
.pics-mosaic + *,
.pics-aside + * { margin-top: 3rem; }
.section-head + .pics-pair,
.section-head + .pics-duo,
.section-head + .pics-mosaic { margin-top: 0.75rem; }

@media (max-width: 899px) {
  .pics-aside { display: block; }
  .pics-aside > * + * { margin-top: 2rem; }
}
@media (max-width: 759px) {
  .pics-pair,
  .pics-duo,
  .pics-mosaic { display: block; }
  .pics-pair > * + *,
  .pics-duo > * + * { margin-top: 2.25rem; }
  .pics-mosaic > :nth-child(n + 2) { margin-top: 2.25rem; }
}

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

.section { padding: clamp(3.5rem, 6vw, 5.5rem) 0; }
.section-first { padding-top: 0.5rem; }
.section-head { margin-bottom: 1.75rem; }
.section-head p { max-width: 62ch; margin-bottom: 0; }
/* Two arrangements on the 12-column grid for sections whose text would
   otherwise sit in the left half: the head beside the list, or the prose
   beside its sources. */
.split,
.split-sources {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}
.split > .section-head { grid-column: 1 / 6; }
.split > :not(.section-head) { grid-column: 7 / 13; }
.split-sources > .section-head { grid-column: 1 / -1; }
.split-sources > .prose { grid-column: 1 / 8; }
.split-sources > .source-list { grid-column: 9 / 13; }
@media (max-width: 899px) {
  .split,
  .split-sources { display: block; }
}

/* ---------- inner pages: the first screen ---------- */

/* The title runs across the top. Under it, on the 12-column grid, the lede
   takes columns 1 to 7 and the page's one figure columns 8 to 12: set at the
   title step, its last baseline on the lede's, its caption beneath. On a
   phone the figure follows the lede at 34vw. */
.page-head { padding: 3rem 0 1rem; }
.page-head-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
}
.page-head h1 { grid-column: 1 / -1; grid-row: 1; }
.page-head-text {
  grid-column: 1 / 8;
  grid-row: 2;
  align-self: last baseline;
}
.page-head-text > :last-child { margin-bottom: 0; }
.page-figure-num {
  grid-column: 8 / 13;
  grid-row: 2;
  align-self: last baseline;
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--step-title);
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: lining-nums tabular-nums;
}
.page-figure-num.ink-outcome { color: var(--chart-orange); }
.page-figure-num.is-bad { color: var(--bad); }
.page-figure-caption {
  grid-column: 8 / 13;
  grid-row: 3;
  margin: 0.85rem 0 0;
  font-size: var(--fs-small);
  line-height: 1.4;
}
/* Updates: the latest entry, in full, is the right column, its last line
   level with the lede's. On a phone it follows the lede. Its date is the
   screen's last line, so the list's heading keeps a clear distance from it. */
.page-head:has(.page-head-latest) { padding-bottom: 2.5rem; }
/* The entry takes six columns, the title and lede the other six, so the
   empty space under the lede stays below a quarter of the first screen. */
.page-head-latest h1,
.page-head-latest .page-head-text { grid-column: 1 / 7; }
/* The lede sits directly under the title, however long the latest entry:
   the title's row keeps its own height, the lede's row takes whatever extra
   the two-row entry needs, and the lede holds the top of it. */
.page-head-latest { grid-template-rows: auto 1fr; }
.page-head-latest .page-head-text { align-self: start; }
.page-latest {
  grid-column: 7 / 13;
  grid-row: 1 / 3;
  align-self: end;
  scroll-margin-top: 1.5rem;
}
.page-latest-title {
  margin: 0 0 0.6rem;
  font-family: var(--display);
  font-size: var(--fs-lede);
  font-weight: 400;
  line-height: 0.95;
  letter-spacing: 0;
  text-transform: uppercase;
}
.page-latest-text { margin: 0; }
.page-latest-date {
  margin: 0.6rem 0 0;
  font-size: var(--fs-small);
  color: var(--ink-2);
}
@media (max-width: 599px) {
  .page-head-grid { display: block; }
  .page-figure-num {
    margin-top: 2.25rem;
    font-size: 34vw;
    white-space: normal;
    letter-spacing: -0.04em;
  }
  .page-figure-caption { margin-top: 0.75rem; }
  .page-latest { margin-top: 2.5rem; }
}

/* ---------- inner pages: section compositions ---------- */

/* A section set on the first tone step, edge to edge. Its charts take the
   field as their ground; its tables step one tone further. */
.section-field {
  background: var(--surface);
  --chart-ground: var(--surface);
}
.section-field table:not(.ledger-table):not(.lineup) tbody tr:nth-child(odd) { background: var(--surface-2); }

/* Text with its sources or a short aside beside it: columns 1 to 7 and 9
   to 12. Always two children. */
.text-aside {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
  margin-top: 1.75rem;
}
.text-aside > :first-child { grid-column: 1 / 8; }
.text-aside > :last-child { grid-column: 9 / 13; }
.text-aside > * > :last-child { margin-bottom: 0; }
/* A chart's caption with the chart's sources beside it: directly under the
   chart, level with the first source. */
.chart-block + .text-aside { margin-top: 0.75rem; }
.text-aside > .chart-caption { margin-top: 0; }
@media (max-width: 899px) {
  .text-aside { display: block; }
  .text-aside > * + * { margin-top: 1.5rem; }
}

/* A dated record: the date in the left rail at the lead step, the entry
   beside it to the right margin. The updates log sets its date small. */
.sequence { list-style: none; margin: 0; padding: 0; }
.sequence > li {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: baseline;
  margin: 0 0 1.75rem;
}
.sequence > li:last-child { margin-bottom: 0; }
.sequence-date {
  grid-column: 1 / 4;
  margin: 0;
  font-family: var(--display);
  font-size: var(--fs-lede);
  font-weight: 400;
  line-height: 0.95;
  text-transform: uppercase;
  font-variant-numeric: lining-nums tabular-nums;
}
.sequence-body { grid-column: 4 / 13; max-width: 72ch; }
.sequence-body > * { margin: 0; }
.sequence-body > * + * { margin-top: 0.45rem; }
.sequence-log > li { margin-bottom: 2.75rem; scroll-margin-top: 1.5rem; }
.sequence-log .sequence-date {
  font-family: var(--text);
  font-size: var(--fs-small);
  line-height: 1.45;
  text-transform: none;
  color: var(--ink-2);
}
.sequence-log h3 { margin: 0; }
@media (max-width: 759px) {
  .sequence > li { display: block; }
  .sequence-date { margin-bottom: 0.4rem; }
}

/* Figures beside the text: the text in columns 1 to 7, the figures stacked
   in 9 to 12. Below 900px the figures come first, two to a row. */
.figure-aside {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
  margin-top: 1.75rem;
}
.figure-aside-text { grid-column: 1 / 8; grid-row: 1; }
.figure-aside-text > :last-child { margin-bottom: 0; }
.figure-stack {
  grid-column: 9 / 13;
  grid-row: 1;
  display: grid;
  gap: 2rem;
  align-content: start;
}
@media (max-width: 899px) {
  .figure-aside { display: flex; flex-direction: column; gap: 2rem; }
  .figure-stack { order: -1; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem var(--gutter); }
}

/* Two columns side by side, seven parts to five: two short essays with their
   own headings, or two paragraphs set as a pair. Stacked below 900px, with a
   section's distance between them so the end of one never reads as a label
   on the next one's heading. */
.duo {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  column-gap: calc(2 * var(--gutter));
  row-gap: 3rem;
  align-items: start;
}
.duo > * { margin: 0; }
.duo > * > :last-child { margin-bottom: 0; }
.duo + .text-aside { margin-top: 2.5rem; }
@media (max-width: 899px) {
  .duo { grid-template-columns: minmax(0, 1fr); row-gap: 1em; }
  .duo:has(> * > h2) { row-gap: 5.5rem; }
}

/* Terms: the term in columns 1 to 4, its definition in 5 to 12. */
.definitions { list-style: none; margin: 0; padding: 0; }
.definitions li {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: baseline;
  margin: 0 0 1.5rem;
}
.definitions li:last-child { margin-bottom: 0; }
.definitions .def-term { grid-column: 1 / 5; font-weight: 600; }
.definitions .def-text { grid-column: 5 / 13; }
@media (max-width: 759px) {
  .definitions li { display: block; }
  .definitions .def-term { display: block; margin-bottom: 0.2rem; }
}

/* Sources set in two columns where the list is long. */
@media (min-width: 900px) {
  .source-list-cols { columns: 2; column-gap: calc(2 * var(--gutter)); }
  .source-list-cols li { break-inside: avoid; }
}

/* Methodology: the three evidence tiers as flat bands, one tone apart, edge
   to edge, each name at the head step beside its definition. */
.tier-bands { margin-top: 2.5rem; }
.tier-band { background: var(--surface); }
.tier-band:nth-child(2) { background: var(--surface-2); }
.tier-band:nth-child(3) { background: var(--surface-3); }
.tier-band-inner {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: baseline;
  padding-top: 2.5rem;
  padding-bottom: 2.5rem;
}
.tier-band h2 { grid-column: 1 / 8; margin: 0; }
.tier-band p { grid-column: 8 / 13; margin: 0; }
@media (max-width: 899px) {
  .tier-band-inner { display: block; padding-top: 2rem; padding-bottom: 2rem; }
  .tier-band h2 { margin-bottom: 0.6rem; }
}

/* Documents: the archive as a line-up, one row per collection at the lead
   step (name, count, toggle), its table opening beneath. The count and
   toggle columns are set in em from the longest of each ("104 documents,
   newest first" is 10.6em, "Show the list" 4.9em), so every row holds one
   line from 960px up and the counts share one left edge. */
.drawer > summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 10.75em 5em;
  column-gap: var(--gutter);
  align-items: baseline;
  padding: 0.55rem 0;
  font-size: var(--fs-lede);
  line-height: 1.3;
  cursor: pointer;
  list-style: none;
}
.drawer > summary::-webkit-details-marker { display: none; }
.drawer-name {
  margin: 0;
  font-family: var(--text);
  font-size: inherit;
  font-weight: 400;
  line-height: inherit;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.drawer-count { color: var(--ink-2); }
.drawer-toggle { justify-self: end; color: var(--accent); }
.drawer-toggle .when-open { display: none; }
.drawer[open] .drawer-toggle .when-open { display: inline; }
.drawer[open] .drawer-toggle .when-closed { display: none; }
.drawer > summary:hover .drawer-name { color: var(--accent); }
.drawer .acc-inner > table { margin-bottom: 2.5rem; }
@media (max-width: 959px) {
  .drawer > summary {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 0.1rem;
    padding: 0.7rem 0;
  }
  .drawer-name { grid-column: 1 / -1; }
  .drawer-count { grid-column: 1; font-size: var(--fs-small); }
  .drawer-toggle { grid-column: 2; font-size: var(--fs-small); }
}

/* ---------- figures (Bebas, head step) ---------- */

.pf { min-width: 0; }
.pf-num {
  font-family: var(--display);
  font-weight: 400;
  font-size: var(--fs-figure);
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.pf-num.is-bad { color: var(--bad); }
.pf-num.ink-outcome { color: var(--chart-orange); }
.pf-label { color: var(--ink-2); font-size: var(--fs-small); line-height: 1.4; margin-top: 0.35rem; }

/* ---------- project rows (projects index) ---------- */

.project-list { display: grid; gap: 1rem; }
/* Name, then the figures, then the area, status and summary. Each row is a
   filled surface; its 5px edge is the key to the map above, in the
   project's map colour. */
.project-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  padding: 1.5rem 1.5rem 1.6rem 1.35rem;
  background: var(--surface);
  border-left: 5px solid var(--project-accent, var(--accent));
  border-radius: 0 12px 12px 0;
  text-decoration: none;
  color: var(--ink);
  transition: background-color var(--t-hover) ease;
}
.project-row[data-project="south-bpc-resiliency"] { --project-accent: var(--hue-south); }
.project-row[data-project="north-west-bpc-resiliency"] { --project-accent: var(--hue-northwest); }
.project-row[data-project="battery-coastal-resilience"] { --project-accent: var(--hue-wharf); }
.project-row[data-project="bpc-ball-fields"] { --project-accent: var(--hue-fields); }
.project-row[data-project="battery-playscape"] { --project-accent: var(--hue-playscape); }
.project-row:hover,
.project-row.is-hot { background: var(--surface-2); }
.project-row:hover h3,
.project-row.is-hot h3 { color: var(--accent); }
.project-row > div:first-child { display: contents; }
.project-row h3 { order: 1; margin: 0 0 1rem; }
.project-figures { order: 2; margin: 0 0 1.1rem; }
.project-row .meta { order: 3; color: var(--ink-2); font-size: var(--fs-small); margin: 0; }
.project-row .meta + .meta { margin-top: 0.5rem; }
.project-row .summary { order: 4; margin: 0.75rem 0 0; max-width: 62ch; }
.project-figures {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 1.25rem 2.5rem;
}
.project-figures .pf { min-width: 7ch; }
.project-figures .pf-spark { order: 9; }
.section-flush { padding-top: 0; }

/* ---------- status: plain text ---------- */

.status {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--ink);
}

/* ---------- project detail ---------- */

.project-header { padding: 3rem 0 2rem; }
/* Status, agency and area (or evidence tier and scope) under a title. */
.meta-line {
  color: var(--ink-2);
  font-size: var(--fs-small);
  margin-top: 0.75rem;
  display: flex;
  gap: 0.65rem;
  align-items: baseline;
  flex-wrap: wrap;
}
.meta-line > span + span::before {
  content: "·";
  margin-right: 0.65rem;
  color: var(--ink-muted);
}
.meta-line + .lede { margin-top: 1.25rem; }
@media (max-width: 599px) {
  .meta-line { display: block; }
  .meta-line > span { display: block; }
  .meta-line > span + span::before { content: none; }
}

/* Figures in a row, unboxed. On a project page the four run across the full
   width at 960px and up (what was promised in blue, what happened in orange,
   pair by pair), and two by two below. */
.figure-band {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.25rem var(--gutter);
  margin: 2.5rem 0 0;
}
@media (min-width: 960px) {
  .project-header .figure-band {
    grid-template-columns: repeat(4, minmax(min-content, max-content));
    justify-content: space-between;
  }
  .project-header .pf-num { white-space: nowrap; }
  .figure-band-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 599px) {
  .figure-band { gap: 1.5rem 1rem; margin-top: 2rem; }
}

/* Charts come in three drawings (lib/charts.js): the wide one at 720 units,
   a medium one at 550 and a phone one at 330, so their labels never render
   under 14px. Each chart block is a size container and shows the drawing that
   suits its own width (a home chart in its 8-of-12 column is narrower than
   the screen suggests): the phone drawing under 600px, the medium one from
   600 to 839px, the wide one from 840px. The rules cascade, each later
   threshold replacing the earlier drawing, so exactly one shows at every
   width. Without container queries the old viewport rule applies. None
   scrolls sideways. Chart text inherits EB Garamond; its figures are lining
   and tabular. Every chart sits unboxed on its section's ground, its caption
   directly under it; the surface colour it draws its halos in is that ground
   (--chart-ground). */
.chart-block { margin: 1.25rem 0 0; container-type: inline-size; }
.chart {
  --surface: var(--chart-ground);
  width: 100%;
  height: auto;
  display: block;
}
.chart .mark {
  cursor: pointer;
  transition: filter 0.12s ease, opacity 0.12s ease;
}
.chart .mark:hover,
.chart a.chart-link:hover .mark {
  filter: brightness(1.12) saturate(1.08);
}
/* A linked row's text takes the accent under the pointer; an overrun or a
   slip keeps its red, which is the figure's meaning. */
.chart a.chart-link:hover text:not(.chart-bad) {
  fill: var(--accent);
}
/* Find your building marks the chosen segments on the esplanade map and
   calendar: the rest step back to 30% while the chosen keep full strength. */
.chart [data-segment] { transition: opacity 200ms ease, filter 0.12s ease; }
.chart.has-choice [data-segment]:not(.is-chosen) { opacity: 0.3; }
.chart-narrow { display: none; max-width: 30rem; }
.chart-medium { display: none; }
@supports (container-type: inline-size) {
  .chart-block > .chart-wide,
  .chart-block > .chart-medium { display: none; }
  .chart-block > .chart-narrow { display: block; }
  @container (min-width: 600px) {
    .chart-block > .chart-narrow { display: none; }
    .chart-block > .chart-medium { display: block; }
  }
  @container (min-width: 840px) {
    .chart-block > .chart-medium { display: none; }
    .chart-block > .chart-wide { display: block; }
  }
}
@supports not (container-type: inline-size) {
  @media (max-width: 680px) {
    .chart-wide { display: none; }
    .chart-narrow { display: block; }
  }
}
.chart-caption {
  color: var(--ink-2);
  font-size: var(--fs-small);
  margin-top: 0.75rem;
  max-width: 96ch;
}

/* ---------- tables: no lines; every other row on the first tone step ---------- */

details.data-table { margin-top: 0.75rem; }
details.data-table summary {
  cursor: pointer;
  color: var(--accent);
  font-size: var(--fs-small);
  font-weight: 500;
}
/* Drawers (these tables and the documents archive) open with the accordion
   recipe: the table sits in one grid row that grows from 0fr to 1fr (the
   opening move is in the motion section). The inner box clips while it
   grows; its side padding holds the table's hanging tone, so nothing is cut
   at rest. */
.acc-panel { display: grid; grid-template-rows: 1fr; }
.acc-inner {
  min-height: 0;
  overflow: hidden;
  margin-inline: calc(-1 * var(--cell-pad));
  padding-inline: var(--cell-pad);
}
table {
  width: calc(100% + 2 * var(--cell-pad));
  border-collapse: collapse;
  margin: 0.75rem calc(-1 * var(--cell-pad)) 0;
}
th {
  text-align: left;
  color: var(--ink-2);
  font-weight: 600;
  padding: 0.5rem var(--cell-pad);
  vertical-align: bottom;
}
td {
  padding: 0.55rem var(--cell-pad);
  vertical-align: top;
}
table:not(.ledger-table):not(.lineup) tbody tr:nth-child(odd) { background: var(--surface); }
td.num, th.num { text-align: right; }
.doc-date { white-space: nowrap; }
/* On a phone the cells tighten and a long linked hostname may break, so no
   table is wider than the screen. Plain text keeps its words whole. */
@media (max-width: 599px) {
  :root { --cell-pad: 6px; }
  td { overflow-wrap: break-word; }
  td a { overflow-wrap: anywhere; }
  /* A wide table opened on a phone scrolls inside its own disclosure
     instead of widening the page. */
  details.data-table .acc-inner { overflow: auto hidden; margin-inline: 0; padding-inline: 0; }
  details.data-table table { width: 100%; margin-inline: 0; }
}

/* Documents: on a phone each row is a block, the date and the archived copy
   on the first line, the title, then the original link. */
@media (max-width: 599px) {
  .doc-table,
  .doc-table tbody { display: block; width: auto; }
  .doc-table thead { display: none; }
  .doc-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1rem;
    padding: 0.65rem var(--cell-pad);
  }
  .doc-table td { padding: 0; }
  .doc-date { grid-column: 1; grid-row: 1; color: var(--ink-2); font-size: var(--fs-small); }
  .doc-archived { grid-column: 2; grid-row: 1; text-align: right; font-size: var(--fs-small); }
  .doc-title { grid-column: 1 / -1; grid-row: 2; margin-top: 0.15rem; }
  .doc-original { grid-column: 1 / -1; grid-row: 3; margin-top: 0.15rem; font-size: var(--fs-small); }
  .doc-original::before { content: attr(data-label) " "; color: var(--ink-2); }
}

/* Get involved: the officials. On a phone each row is two lines, the role
   first, then the name and the link. */
.officials td { vertical-align: baseline; }
@media (max-width: 599px) {
  .officials,
  .officials tbody { display: block; }
  .officials thead { display: none; }
  .officials tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1rem;
    padding: 0.7rem var(--cell-pad);
  }
  .officials td { padding: 0; }
  .officials-role { grid-column: 1 / -1; color: var(--ink-2); }
  .officials-name { grid-column: 1; }
  .officials-link { grid-column: 2; text-align: right; }
}

/* ---------- promised vs delivered ---------- */

.pvd {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2rem calc(2 * var(--gutter));
}
@media (max-width: 780px) { .pvd { grid-template-columns: 1fr; } }
.pvd h3 { margin-bottom: 0.9rem; }
.pvd ul { list-style: none; margin: 0; padding: 0; }
.pvd li { margin: 0 0 1em; }
.pvd li:last-child { margin-bottom: 0; }
/* Evidence labels: plain small text in their colour, nothing around them. */
.tag {
  display: inline-block;
  font-size: var(--fs-small);
  font-weight: 600;
  margin-right: 0.5rem;
  color: var(--ink-muted);
}
.tag::first-letter { text-transform: uppercase; }
/* Inside running text a label is a defined term: the sentence's size, lower case. */
.lede .tag { display: inline; font-size: inherit; margin-right: 0; }
.tag.kept { color: var(--good); }
.tag.changed { color: var(--bad); }
.tag.pending { color: var(--accent); }
.tag.documented { color: var(--accent); }
.tag.observed { color: var(--ink-2); }
.tag.wip { color: var(--ink-muted); }

/* ---------- issues / sources ---------- */

.issue-list { list-style: none; margin: 0; padding: 0; max-width: 72ch; }
.issue-list li { margin: 0 0 1.1em; }
.issue-list li:last-child { margin-bottom: 0; }
.source-ref { font-size: var(--fs-small); color: var(--ink-2); margin-top: 0.2rem; }

.source-list { list-style: none; margin: 0; padding: 0; font-size: var(--fs-small); }
.source-list li { margin: 0 0 0.9em; }
.source-list li:last-child { margin-bottom: 0; }
.source-list .src-meta { color: var(--ink-muted); }
/* A project page's Sources section is running text in its own right, so it
   sits at the body step; the hostname and date note stays small. */
.source-list-body { font-size: var(--fs-body); }
.source-list-body .src-meta { font-size: var(--fs-small); }

/* ---------- get involved ---------- */

/* Put it in writing: three bands of flat colour, each one tone step from the
   last, edge to edge. */
.section-bands { padding-bottom: 0; }
.tone-bands { margin-top: 2.25rem; }
.tone-band { background: var(--surface); }
.tone-band:nth-child(2) { background: var(--surface-2); }
.tone-band:nth-child(3) { background: var(--surface-3); }
.tone-band-inner {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 0.75rem;
  padding-top: 3rem;
  padding-bottom: 3rem;
}
.tone-band h3 { grid-column: 1 / 6; margin: 0; }
.tone-band-body { grid-column: 6 / 13; }
.tone-band-body p { margin: 0; max-width: 62ch; }
.tone-band-body .tone-band-link { margin-top: 0.75rem; }
@media (max-width: 759px) {
  .tone-band-inner { display: block; padding-top: 2.25rem; padding-bottom: 2.25rem; }
  .tone-band h3 { margin-bottom: 0.75rem; }
}

/* Follow the coverage: a plain list, the name at the lead step. */
.coverage-list { list-style: none; margin: 0; padding: 0; }
.coverage-list li {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  margin: 0 0 2rem;
}
.coverage-name { grid-column: 1 / 5; margin: 0; }
.coverage-body { grid-column: 5 / 13; }
.coverage-body p { margin: 0; max-width: 62ch; }
.coverage-body .coverage-link { margin-top: 0.35rem; }
@media (max-width: 759px) {
  .coverage-list li { display: block; }
  .coverage-name { margin-bottom: 0.5rem; }
}

.notify-band {
  background: var(--accent-soft);
  border-radius: 12px;
  padding: 1.75rem;
  margin-top: 3rem;
}
/* The band beside the BPCA's own notice boards. */
.notify-aside { margin-top: 3rem; }
.notify-aside .notify-band { margin-top: 0; }
.notify-band h3 { margin-top: 0; }
.notify-band ul { margin: 0; padding-left: 1.2rem; }
.notify-band li { margin-bottom: 0.45em; }

/* ---------- impacts: the areas as a list set large (capabilities) ---------- */

.capability-list { list-style: none; margin: 0; padding: 0; }
.capability-list li { margin: 0 0 3rem; }
.capability-list li:last-child { margin-bottom: 0; }
.capability {
  font-size: var(--fs-h2);
  margin: 0 0 0.3rem;
}
/* Links set in Bebas at the head step or above carry no underline at rest:
   hover and focus bring the accent and a 3px underline 3px below the
   baseline. Inline links in running text keep their underline. */
.capability a {
  color: var(--ink);
  text-decoration: none;
}
.capability a:hover,
.capability a:focus-visible {
  color: var(--accent);
  text-decoration-line: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 3px;
}
.capability-list p { margin: 0; max-width: 60ch; }
.capability-list-small li { margin-bottom: 2rem; }
.capability-list-small .capability { font-size: var(--fs-lede); line-height: 0.95; margin-bottom: 0.4rem; }
/* The case files are set at the lead step, below display size, and keep a
   resting underline. */
.capability-list-small .capability a,
.page-latest-title a {
  color: var(--ink);
  text-decoration-line: underline;
  text-decoration-color: color-mix(in srgb, var(--ink) 30%, transparent);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.12em;
}
.capability-list-small .capability a:hover,
.capability-list-small .capability a:focus-visible,
.page-latest-title a:hover,
.page-latest-title a:focus-visible {
  color: var(--accent);
  text-decoration-color: currentColor;
}

/* ---------- updates ---------- */

.update-list { list-style: none; margin: 0; padding: 0; max-width: 72ch; }
.update-list li { margin: 0 0 2.5rem; }
.update-list li:last-child { margin-bottom: 0; }
.update-date { color: var(--ink-2); font-size: var(--fs-small); margin: 0 0 0.35rem; }
.update-list h3 { margin: 0 0 0.45rem; }
.update-list p { margin: 0; max-width: 64ch; }

/* ---------- closures: Find your building (the live thing) ---------- */

/* Without script, a list: each building's frontage with its closure window.
   With building.js (.is-live) a native select opens on "Choose your building":
   no result yet, and the map and the calendar below untouched. Choosing a
   building shows its result (and sets .has-choice here), keeps the choice in
   the URL (#building=<id>), and marks its segments on the map and the
   calendar. */
.finder { margin-top: 3.5rem; scroll-margin-top: 1.5rem; }
.finder [hidden] { display: none !important; }
.finder-label {
  display: block;
  margin: 0 0 0.85rem;
  font-family: var(--display);
  font-size: var(--fs-lede);
  line-height: 0.95;
  text-transform: uppercase;
  color: var(--ink);
}
/* The field: flat, one tone step from the ground, thumb-sized; the press
   gives a little; focus brings the accent (the ring and the chevron). */
.finder-field {
  position: relative;
  width: min(100%, 24rem);
  transition: transform var(--t-press) var(--ease-out);
}
.finder-field:has(.finder-select:active) { transform: scale(0.97); }
.finder-select {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  min-height: 48px;
  margin: 0;
  padding: 0.6rem 3rem 0.6rem 1rem;
  font-family: var(--text);
  font-size: var(--fs-body);
  line-height: 1.3;
  color: var(--ink);
  background: var(--surface);
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color var(--t-hover) ease;
}
@media (hover: hover) and (pointer: fine) {
  .finder-select:hover { background: var(--surface-2); }
}
.finder-chevron {
  position: absolute;
  top: 50%;
  right: 1rem;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  color: var(--ink-2);
  pointer-events: none;
  transition: color var(--t-hover) ease;
}
.finder-field:focus-within .finder-chevron { color: var(--accent); }
/* The result: how long (the figure, head step) over where (small, the
   figure's label, as everywhere on the site), then from and to, and whether
   the building has signed its construction agreement (in the outcome ink
   when it has not). */
.finder-results { margin-top: 2.25rem; }
.finder-result + .finder-result { margin-top: 3rem; }
.finder-building { margin: 0 0 1rem; }
.finder-segments {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.25rem var(--gutter);
}
.finder-segment > * { margin: 0; }
.finder-where { margin-top: 0.5rem; font-size: var(--fs-small); color: var(--ink-2); }
.finder-months {
  font-family: var(--display);
  font-size: var(--fs-h2);
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.finder-when { margin-top: 0.85rem; }
.finder-agreement { margin-top: 0.15rem; }
/* The map and the calendar below answer the choice: a section-head's
   distance from the result. */
.finder + .chart-block { margin-top: 3.5rem; }
/* Live: the results share one grid cell, so the chosen one and the one it
   replaces cross-fade in place over 200ms, and the first choice fades its
   result in the same way (all instant with motion reduced). The select names
   the building, so the result's own heading stays for screen readers only.
   Nothing chosen, the results box stays (it is the live region) but empty, and
   gives back its margin: the select sits the map's own distance from the map. */
.finder.is-live .finder-results { display: grid; }
.finder.is-live:not(.has-choice) .finder-results { margin-top: 0; }
.finder.is-live .finder-result {
  grid-area: 1 / 1;
  margin-top: 0;
  transition: opacity 200ms ease;
}
.finder.is-live .finder-result.is-entering,
.finder.is-live .finder-result.is-leaving { opacity: 0; }
@media (max-width: 759px) {
  .finder-segments { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 599px) {
  .finder { margin-top: 2.75rem; }
  .finder-field { width: 100%; }
  .finder-months { letter-spacing: -0.04em; }
}

/* ---------- footer (contact blueprint "Contact as the headline") ---------- */

.site-footer {
  background: var(--inverse);
  color: var(--on-inverse);
}
.site-footer a { color: var(--on-inverse); }
.site-footer a:focus-visible { outline-color: var(--on-inverse); }
/* At least 90svh on desktop: the notes at the top, the contact line in the
   lower half, the small row at the foot. */
.footer-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(64px, 3fr) auto minmax(24px, 2fr) auto;
  min-height: 90svh;
  padding-top: 40px;
  padding-bottom: 40px;
}
.is-home .footer-inner {
  max-width: none;
  padding-inline: var(--edge);
}
.footer-top {
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: start;
}
.footer-notes {
  grid-column: 1 / 8;
  font-size: var(--fs-small);
  line-height: 1.45;
}
.footer-notes p { margin: 0 0 0.5rem; max-width: 72ch; }
.footer-notes p:last-child { margin-bottom: 0; }
.footer-brand { font-weight: 600; }
.footer-totop {
  grid-column: 9 / 13;
  justify-self: end;
  font-size: var(--fs-small);
  white-space: nowrap;
}
/* The corrections address is the display line, one link, on two lines:
   "Corrections:" over the address. Inner pages and every phone set it at the
   title step; the home page sets it at the statement's display step. At rest
   it carries no underline; hover and focus bring the accent (in its inverse
   form) and a 3px underline 3px below the baseline. */
.footer-contact {
  grid-row: 3;
  margin: 0;
  font-family: var(--display);
  font-size: var(--step-title);
  font-weight: 400;
  line-height: 0.85;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}
.fc-label { display: block; }
.footer-contact a { text-decoration: none; }
.footer-contact a:hover,
.footer-contact a:focus-visible {
  color: var(--accent-on-inverse);
  text-decoration-line: underline;
  text-decoration-thickness: 3px;
  text-underline-offset: 3px;
}
.is-home .footer-contact {
  font-size: var(--step-display);
  letter-spacing: -0.04em;
}
/* The small row: links at the left, city and year at the right, and under
   them the credit line of every picture on the page, one line each, in two
   columns on a wide screen. */
.footer-meta {
  grid-row: 5;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: 2rem;
  row-gap: 1.5rem;
  margin-top: 24px;
  font-size: var(--fs-small);
}
.footer-links { display: flex; flex-wrap: wrap; gap: 0.4rem 1.25rem; }
.footer-place { justify-self: end; margin: 0; }
.credits {
  grid-column: 1 / -1;
  grid-row: 2;
  display: block;
  columns: 2;
  column-gap: calc(2 * var(--gutter));
  line-height: 1.45;
}
.credits:empty { display: none; }
.credits-head,
.credit {
  display: block;
  break-inside: avoid;
  margin: 0 0 0.4rem;
}
.credits-head { font-weight: 600; column-span: all; }
@media (max-width: 959px) {
  .credits { columns: 1; }
}
@media (max-width: 1099px) {
  .footer-inner {
    min-height: 0;
    grid-template-rows: auto 120px auto 0 auto;
  }
}
@media (max-width: 599px) {
  .footer-inner { grid-template-rows: auto 96px auto 0 auto; padding-top: 32px; padding-bottom: 32px; }
  .footer-top { display: block; }
  .footer-notes p { margin-bottom: 0.6rem; }
  .footer-totop { display: inline-block; margin-top: 0.75rem; }
  .footer-contact,
  .is-home .footer-contact {
    font-size: var(--step-title);
    letter-spacing: -0.04em;
  }
  .footer-meta { grid-template-columns: minmax(0, 1fr); }
  .credits { grid-row: 3; }
  .footer-place { justify-self: start; }
}

/* ---------- locator map (projects index), unboxed ---------- */

.projects-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 27rem);
  gap: 1.5rem 3rem;
  align-items: start;
}
.projects-intro .lede { margin-bottom: 0; }
@media (max-width: 899px) {
  .projects-intro { grid-template-columns: minmax(0, 1fr); }
  .projects-intro .locator { max-width: 27rem; }
}
.locator { margin: 0; }
.locator-svg {
  width: 100%;
  height: auto;
  display: block;
}
.locator figcaption {
  color: var(--ink-2);
  font-size: var(--fs-small);
  margin: 0.75rem 0 0;
}
.map-region {
  cursor: pointer;
}
.map-region path {
  fill: var(--hue);
  fill-opacity: 0.42;
  stroke: var(--hue);
  stroke-width: 2;
  transition: fill-opacity 0.15s ease, filter 0.15s ease;
}
.map-region .map-label {
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  fill: var(--ink);
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 4px;
  stroke-linejoin: round;
  pointer-events: none;
}
.map-region:hover path,
.map-region:focus-visible path,
.map-region.is-hot path {
  fill-opacity: 0.7;
  filter: saturate(1.1);
}
.map-region:focus-visible {
  outline: none;
}
.map-region:focus-visible path {
  stroke-width: 3;
}

/* ---------- sparklines and growth track ---------- */

.sparkline {
  width: 128px;
  height: 36px;
  display: block;
}
.pf-spark { min-width: 8.5rem; }
.growth-track {
  margin-top: 0.4rem;
  height: 6px;
  border-radius: 99px;
  background: var(--bad-soft);
  overflow: hidden;
}
.growth-orig {
  display: block;
  height: 100%;
  background: var(--chart-blue);
  border-radius: 99px;
}

/* ---------- chart tooltip ---------- */

.chart-tooltip {
  position: fixed;
  z-index: 50;
  max-width: min(22rem, calc(100vw - 1.5rem));
  padding: 0.45rem 0.7rem;
  background: var(--ink);
  color: var(--page);
  font-size: var(--fs-small);
  line-height: 1.4;
  border-radius: 8px;
  pointer-events: none;
  white-space: normal;
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink) 25%, transparent); /* taste-skill-ignore: the tooltip floats */
}

/* ---------- motion ---------- */

/* Every element is in the HTML and painted in its finished place; motion
   only adds arrival. Each hidden starting state below lives under html.js
   (set by the inline script in base.njk, taken off again if enhance.js never
   runs) inside prefers-reduced-motion: no-preference, so without script, or
   with motion reduced, nothing waits and nothing hides. Transform, opacity
   and clip-path only (and grid rows for the drawers, and a chart line's
   dash offset). enhance.js adds .is-in once, as soon as any part of an
   element is on screen, and sets --d, its step: 70ms apart in reading
   order, four steps at most (a chart takes no step of its own). */

/* Rolling figures (enhance.js builds them only when motion is allowed): each
   digit is a column of 0 to 9 that rolls up to its value once, seen through
   its own line box, so a passing digit never crosses the lines above or
   below. Bebas Neue's digits run from 0.71em above the baseline to 0.01em
   below it, which in these figures' 0.8 and 0.85 line boxes leaves them
   between 0.01em above the box and 0.12em inside its foot: the mask opens
   0.04em at the top, and a strip's pitch is one line plus 0.1em so the
   next digit stays below the foot. */
.roll-word { white-space: nowrap; }
.roll-col {
  display: inline-block;
  position: relative;
  vertical-align: top;
  height: 1lh;
  clip-path: inset(-0.04em -0.05em 0 -0.05em);
}
.roll-ghost { visibility: hidden; }
.roll-strip {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  text-align: center;
  transform: translateY(calc(var(--n) * (-1lh - 0.1em)));
}
.roll-strip > span { display: block; height: calc(1lh + 0.1em); }

/* A headline whose line breaks are authored: one box per line, the mask. */
.lines .line,
.lines [data-line] { display: block; }

@keyframes line-rise { from { transform: translateY(110%); } }
@keyframes load-rise { from { opacity: 0; transform: translateY(var(--rise, 24px)); } }
@keyframes drift { to { transform: scale(1.06); } }

@media (prefers-reduced-motion: no-preference) {
  /* The signature move: each line rises from behind its own baseline, 900ms
     on the expo curve, the second 110ms after the first. The mask is the
     line's own box, opened well above and to the sides, so nothing at rest
     is clipped. Starts with the first frame, not the load event. */
  .js .lines .line { clip-path: inset(-0.4em -0.4em 0 -0.4em); }
  .js .lines [data-line] {
    animation: line-rise 900ms var(--ease-expo) calc(60ms + var(--i, 0) * 110ms) both;
  }
  /* Home: the sentence and the action arrive together after the lines; the
     whole sequence has settled by 1.1s. */
  .js .is-home .hero-foot > *,
  .js .is-home .header-cta {
    --rise: 12px;
    animation: load-rise 500ms var(--ease-out) 600ms both;
  }
  /* Inner pages: the title and the page's one figure rise together, the
     lede after them. A title with authored lines keeps the mask above. */
  .js .page-head h1,
  .js .page-head .page-figure-num,
  .js .page-head .page-latest,
  .js .project-header h1:not(.lines),
  .js .project-header .figure-band,
  .js .projects-intro .locator {
    animation: load-rise 700ms var(--ease-out) 60ms both;
  }
  .js .page-head .page-head-text,
  .js .page-head .page-figure-caption,
  .js .project-header .meta-line,
  .js .project-header .lede {
    animation: load-rise 600ms var(--ease-out) 240ms both;
  }
  .js .project-header h1.lines ~ .lede { animation-delay: 400ms; }

  /* Rise: a heading, a paragraph, a chart, a list as a whole. */
  .js [data-reveal=""] { opacity: 0; transform: translateY(24px); }
  .js [data-reveal=""].is-in {
    opacity: 1;
    transform: none;
    transition: opacity 600ms var(--ease-out) var(--d, 0ms), transform var(--t-reveal) var(--ease-expo) var(--d, 0ms);
  }

  /* Rows: a line-up, a table or a short list arrives one row after another,
     70ms apart (enhance.js numbers the rows). */
  .js [data-reveal="rows"]:not(table) > *,
  .js table[data-reveal="rows"] > tbody > tr { opacity: 0; transform: translateY(16px); }
  .js [data-reveal="rows"].is-in:not(table) > *,
  .js table[data-reveal="rows"].is-in > tbody > tr {
    opacity: 1;
    transform: none;
    transition:
      opacity 500ms var(--ease-out) calc(var(--d, 0ms) + var(--row, 0) * var(--stagger-item)),
      transform 700ms var(--ease-out) calc(var(--d, 0ms) + var(--row, 0) * var(--stagger-item)),
      background-color var(--t-hover) ease;
  }

  /* Line: the home page's two giant figures rise from behind their own
     baselines (the masked line reveal), 900ms on the expo curve, the second
     110ms after the first, once, as the pair comes on screen. Each starts
     1.05em down, so even the dollar sign's top (0.045em above the line box)
     sits below its mask's foot (0.88em down); the finished state is the
     whole figure, with nothing clipped. */
  .js [data-reveal="line"] [data-line] { transform: translateY(1.05em); }
  .js [data-reveal="line"].is-in [data-line] {
    transform: none;
    transition: transform 900ms var(--ease-expo) calc(var(--d, 0ms) + var(--i, 0) * 110ms);
  }

  /* Bars: a chart whose block carries data-reveal="bars" keeps its frame
     (names, axis, legend, the today line) in place while its marks arrive,
     left to right: each bar grows from its left end (900ms, expo), rows 70ms
     apart and six steps at most, a slip one beat (250ms) after its row; each
     label fades in once its bar has nearly landed. A time series sweeps
     instead: its columns grow down from their first hour and its line draws
     itself, each point appearing as the sweep passes it. lib/charts.js marks
     the parts (data-bar, data-col, data-line, data-point, data-bar-label) and
     numbers them (--row, --lag, --x); enhance.js starts the chart the moment
     any part of it shows. */
  .js [data-reveal="bars"] [data-bar] {
    transform-box: fill-box;
    transform-origin: left center;
    transform: scaleX(0);
  }
  .js [data-reveal="bars"] [data-col] {
    transform-box: fill-box;
    transform-origin: center top;
    transform: scaleY(0);
  }
  .js [data-reveal="bars"] [data-line] { stroke-dasharray: 1; stroke-dashoffset: 1; }
  .js [data-reveal="bars"] [data-bar-label],
  .js [data-reveal="bars"] [data-point] { opacity: 0; }
  .js [data-reveal="bars"].is-in [data-bar] {
    transform: none;
    transition:
      transform 900ms var(--ease-expo) calc(var(--d, 0ms) + min(var(--row, 0), 6) * var(--stagger-item) + var(--lag, 0) * 250ms),
      opacity 200ms ease,
      filter 120ms ease;
  }
  .js [data-reveal="bars"].is-in [data-col] {
    transform: none;
    transition: transform 600ms var(--ease-expo) calc(var(--d, 0ms) + var(--x, 0) * 800ms), filter 120ms ease;
  }
  .js [data-reveal="bars"].is-in [data-line] {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset 1000ms var(--ease-in-out) var(--d, 0ms);
  }
  .js [data-reveal="bars"].is-in [data-bar-label] {
    opacity: 1;
    transition:
      opacity 400ms var(--ease-out) calc(var(--d, 0ms) + min(var(--row, 0), 6) * var(--stagger-item) + var(--lag, 0) * 250ms + 450ms),
      filter 120ms ease;
  }
  .js [data-reveal="bars"].is-in [data-point] {
    opacity: 1;
    transition: opacity 300ms var(--ease-out) calc(var(--d, 0ms) + var(--x, 0) * 800ms + 200ms), filter 120ms ease;
  }

  /* Shutter: the page's first picture group opens from its top edge while
     the image settles from 1.12 inside its frame; the caption follows. The
     opening takes 800ms, not the recipe's 1100ms, so no part of a picture in
     view stays hidden past 900ms. */
  .js [data-reveal="shutter"] .picture-frame { clip-path: inset(0 0 100% 0); }
  .js [data-reveal="shutter"] img { transform: scale(1.12); }
  .js [data-reveal="shutter"] figcaption { opacity: 0; }
  .js [data-reveal="shutter"].is-in .picture-frame {
    clip-path: inset(0);
    transition: clip-path 800ms var(--ease-in-out) var(--d, 0ms);
  }
  .js [data-reveal="shutter"].is-in img {
    transform: none;
    transition: transform 1400ms var(--ease-soft) var(--d, 0ms);
  }
  .js [data-reveal="shutter"].is-in figcaption {
    opacity: 1;
    transition: opacity 500ms var(--ease-out) calc(var(--d, 0ms) + 300ms);
  }

  /* Settle: every later picture fades in while it settles from 1.06. */
  .js [data-reveal="settle"] { opacity: 0; }
  .js [data-reveal="settle"] img { transform: scale(1.06); }
  .js [data-reveal="settle"].is-in {
    opacity: 1;
    transition: opacity 700ms var(--ease-out) var(--d, 0ms);
  }
  .js [data-reveal="settle"].is-in img {
    transform: none;
    transition: transform 1200ms var(--ease-expo) var(--d, 0ms);
  }

  /* Rolling figures: the strips start at 0 and roll once, a column apart. */
  .js .roll:not(.is-in) .roll-strip { transform: none; }
  .js .roll.is-in .roll-strip {
    transition: transform 1000ms var(--ease-expo) calc(var(--d, 0ms) + var(--c, 0) * var(--stagger-item));
  }

  /* The one moving picture: the 1974 landfill drifts from 1 to 1.06 over
     20s and back, linear, only while it is near the screen (away from it,
     it rests at its true size) and paused while the tab is hidden. */
  .js .drift.is-near img { animation: drift 20s linear infinite alternate; }
  .js .drift.is-near.is-paused img { animation-play-state: paused; }

  /* Projects index: each project's estimate-over-time line draws itself
     left to right, the way the years run, as its row arrives. */
  .js .project-list[data-reveal="rows"] .sparkline { clip-path: inset(0 100% 0 0); }
  .js .project-list[data-reveal="rows"].is-in .sparkline {
    clip-path: inset(0);
    transition: clip-path 900ms var(--ease-in-out) calc(var(--d, 0ms) + var(--row, 0) * var(--stagger-item) + 200ms);
  }

  /* Drawers and the phone menu open with the accordion recipe: one grid row
     from 0fr to 1fr in 240ms (the menu also fades in, from where it hangs). */
  details[open] > .acc-panel { transition: grid-template-rows var(--t-ui) var(--ease-out); }
  .nav-menu[open] nav {
    transition: grid-template-rows var(--t-ui) var(--ease-out), opacity var(--t-ui) var(--ease-out);
  }
  @starting-style {
    details[open] > .acc-panel { grid-template-rows: 0fr; }
    .nav-menu[open] nav { grid-template-rows: 0fr; opacity: 0; }
  }
}
