/* ==========================================================================
   OneVill Foundation — design system

   Architecture follows the reference the client pinned: a thin pale utility
   bar above a transparent header over a full-bleed scrimmed hero; deep-ground
   sections carrying large multi-line accent headings; a three-column pillar
   row divided by hairlines; floating white cards with dark buttons; one
   humanist family; generous scale.

   The twist is a hue inversion and a tiled hero. The reference makes green the
   accent over a navy ground with lime as a quiet strip; here deep forest green
   IS the ground and citrus is promoted to the accent. And where the reference
   opens on one photograph, this opens on a repeating wall of twenty-three,
   duotoned to the ground colour — the client's whole library at once instead
   of a single hero shot. Upload SiteSettings.hero_image and the hero falls
   back to the conventional single-photo treatment.
   ========================================================================== */

:root {
  --ground: #0e2a22;
  --ground-2: #143529;
  --ground-3: #1b4232;

  --accent: #c6e86b;
  --accent-deep: #55700f;

  --paper: #f3f1e7;
  --white: #ffffff;

  --ink: #14201a;
  --body: #47544c;
  --muted: #5f6c64;
  --line: #e0dccc;
  --line-dark: rgba(255, 255, 255, 0.16);

  --measure: 68ch;
  --max: 1240px;
  /* Header height. Fixed, never animated: the masthead is sticky, so it holds
     flow space, and shrinking it on scroll would pull the whole document up
     under the scroll position and make the page jump. The logo zooms with a
     transform inside this constant box instead. The hero and every page head
     slide under the bar by exactly this, so it lives in one place. */
  --bar: 6.4rem;

  --r-sm: 6px;
  --r: 12px;
  --r-lg: 22px;
  --r-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(14, 42, 34, 0.06), 0 2px 6px rgba(14, 42, 34, 0.05);
  --shadow: 0 8px 28px rgba(14, 42, 34, 0.10);
  --shadow-lg: 0 24px 60px rgba(14, 42, 34, 0.18);

  --text: "Mulish", system-ui, -apple-system, sans-serif;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

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

html { scroll-behavior: smooth; scroll-padding-top: 8.1rem; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--body);
  font-family: var(--text);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* --- Browser surfaces ------------------------------------------------------ */

::selection { background: var(--accent); color: var(--ink); }
::-moz-selection { background: var(--accent); color: var(--ink); }

:root { scrollbar-color: var(--ground-3) var(--paper); scrollbar-width: thin; }
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--ground-3); border: 3px solid var(--paper); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--ground); }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--accent-deep);
  outline-offset: 2px;
}
.on-ink :where(a, button, input, select, textarea, summary):focus-visible { outline-color: var(--accent); }

input, textarea, select { caret-color: var(--accent-deep); }

.skip {
  position: absolute; left: 1rem; top: -5rem; z-index: 100;
  padding: 0.75rem 1.2rem; background: var(--accent); color: var(--ink);
  font-weight: 700; text-decoration: none; border-radius: var(--r-sm);
  transition: top 0.2s var(--ease);
}
.skip:focus { top: 1rem; color: var(--ink); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* --- Typography ------------------------------------------------------------ */

h1, h2, h3, h4 {
  font-family: var(--text);
  color: var(--ink);
  margin: 0 0 0.5em;
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

h1 { font-size: clamp(2.4rem, 5.4vw, 4.1rem); }
h2 { font-size: clamp(1.9rem, 3.8vw, 3.1rem); }
h3 { font-size: 1.2rem; font-weight: 700; letter-spacing: -0.012em; }
h4 { font-size: 1rem; font-weight: 700; letter-spacing: 0; }

p { margin: 0 0 1.15rem; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-deep); text-decoration-thickness: 1.5px; text-underline-offset: 0.16em; }
a:hover { color: var(--ink); }

strong { color: var(--ink); font-weight: 700; }
img { max-width: 100%; display: block; border-radius: var(--r); }
/* The UA gives figure a 40px side margin, which pushes every framed photograph
   out of its column. */
figure { margin: 0; }
hr { display: none; }

.lede { font-size: clamp(1.08rem, 1.6vw, 1.3rem); line-height: 1.55; color: var(--body); max-width: 46ch; }

.prose { max-width: var(--measure); }
.prose p { white-space: pre-line; }
.prose h2 { margin-top: 2.5rem; font-size: clamp(1.4rem, 2.4vw, 1.9rem); }
.prose h2:first-child { margin-top: 0; }

/* Small meta labels — dates, categories, reference codes. */
.code {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.6;
}
.code--lg { font-size: 0.8rem; color: var(--body); }
.on-ink .code { color: color-mix(in oklab, #fff, transparent 22%); }

.dl-code { display: grid; grid-template-columns: auto 1fr; gap: 0.5rem 1.3rem; margin: 0; align-items: baseline; }
.dl-code dt { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); white-space: nowrap; }
.dl-code dd { margin: 0; color: var(--ink); font-size: 0.98rem; font-weight: 600; }
/* The contact block's address and email are links people tap. */
.dl-code dd a { display: inline-block; padding: 0.15rem 0; }
.on-ink .dl-code dt { color: color-mix(in oklab, #fff, transparent 24%); }
.on-ink .dl-code dd { color: #fff; }

/* --- Page & sections -------------------------------------------------------- */

.page { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 1.75rem; }
.page--narrow { max-width: 780px; }

.leaf { position: relative; padding: clamp(3.5rem, 7vw, 6.5rem) 0; }
.leaf--tight { padding: clamp(2.25rem, 4vw, 3.5rem) 0; }
.leaf--hi { background: var(--white); }
.leaf--green { background: var(--ground-2); }
.leaf--ink { background: var(--ground); }

.on-ink, .leaf--green, .leaf--ink { color: color-mix(in oklab, #fff, transparent 16%); }
.on-ink :is(h1, h2, h3, h4), .leaf--green :is(h1, h2, h3, h4), .leaf--ink :is(h1, h2, h3, h4) { color: var(--accent); }
.on-ink h3, .leaf--green h3, .leaf--ink h3 { color: var(--accent); }
.on-ink .lede, .leaf--green .lede, .leaf--ink .lede { color: color-mix(in oklab, #fff, transparent 10%); }
.on-ink strong, .leaf--green strong, .leaf--ink strong { color: #fff; }
/* Prose links on a deep ground. The context is wrapped in `:where()` so it
   contributes no specificity at all, which leaves these at the weight of a bare
   `a` — and that matters: written as `.on-ink a` this rule was (0,2,0) and beat
   every component class, so a white `.act-press` pill sitting in a dark section
   got citrus text on white at about 1.6:1. Any element with its own class now
   keeps its own colour, and only unstyled prose links pick this up. */
:where(.on-ink, .leaf--green, .leaf--ink) a { color: var(--accent); text-decoration-color: color-mix(in oklab, var(--accent), transparent 55%); }
:where(.on-ink, .leaf--green, .leaf--ink) a:hover { color: #fff; }

/* The reference's dot-and-caps marker, set in the margin beside the heading
   rather than stacked above it. */
.section-label {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent-deep);
}
.section-label::before {
  content: "";
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.on-ink .section-label, .leaf--green .section-label, .leaf--ink .section-label,
.arrivals .section-label, .leaf-top .section-label { color: var(--accent); }

/* Section head: label in a narrow left column, heading and lede at the right. */
.head-split { display: grid; grid-template-columns: minmax(0, 0.34fr) minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 3.5rem); align-items: start; margin-bottom: clamp(2rem, 4vw, 3.25rem); }
.head-split h2 { margin-bottom: 0.4em; }
.head-split .lede { max-width: 52ch; }

.leaf-head { max-width: 32ch; margin-bottom: clamp(1.75rem, 3vw, 2.5rem); }
.leaf-head--wide { max-width: 46ch; }
.leaf-head .lede { margin-top: 0.85rem; }

.anchor-stop { scroll-margin-top: 8rem; }

/* --- Utility bar + header ---------------------------------------------------- */

.utility {
  background: var(--accent);
  color: var(--ink);
  font-size: 0.82rem;
  font-weight: 600;
}
.utility .page { display: flex; align-items: center; justify-content: flex-end; gap: 1.5rem; min-height: 2.4rem; flex-wrap: wrap; }
/* 22px tall as bare links; the bar is short but its two links are still
   controls, so they take the 24px floor too. */
.utility a { color: var(--ink); text-decoration: none; display: inline-flex; align-items: center; min-height: 1.6rem; }
.utility a:hover { text-decoration: underline; text-underline-offset: 0.16em; }

/* Transparent over the hero, solid once you move. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 60;
  background: transparent;
  transition: background 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.masthead .page {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: var(--bar);
}
.masthead.is-lifted { background: var(--ground); box-shadow: 0 1px 0 var(--line-dark); }
/* The logo is shown zoomed while the visitor is at the top of the page, and
   settles to its resting size once they scroll. Scaled rather than resized:
   the layout box stays 4.5rem tall either way, so nothing reflows and the
   transition runs on the compositor. The multiplier is modest because the
   resting size is already large — 1.18 takes the lockup to 85px, which still
   breathes inside the 102px bar, and at the top of the page the masthead is
   transparent over the hero anyway, so there is no bar edge to crowd. */
.masthead .mark-glyph { transform-origin: left center; transform: scale(1.18); }
.masthead.is-lifted .mark-glyph { transform: none; }

.mark { display: inline-flex; align-items: center; gap: 0.7rem; text-decoration: none; color: #fff; flex-shrink: 0; }
.mark:hover { text-decoration: none; color: #fff; }
/* The mark carries the organisation's name, so no name is ever set beside it.
   Both ratios are the drawings' own viewBoxes — `scripts/build_logo.py` prints
   them, so re-read them there if the client's master is replaced.

   Height is set by the descriptor, not by the wordmark. NETHERLANDS is 19px
   inside a 162-unit lockup, which lands under 6px at the 2.5rem a bare wordmark
   needed and reads from about 4.5rem up. That is the floor for showing the
   lockup at all: below it the tag is a green smudge that says nothing, and the
   wordmark on its own is the honest choice instead. */
.mark-glyph {
  height: 4.5rem;
  width: auto;
  aspect-ratio: 2.1808;
  flex-shrink: 0;
  transition: transform 0.3s var(--ease);
}
/* The lockup minus its descriptor, for a surface too narrow to show one. */
.mark-glyph--word { height: 2.5rem; aspect-ratio: 3.47; }
/* The fallbacks baked into the drawing are the reversed set, because the
   masthead and the colophon — the two places the mark appears on the site — are
   deep grounds. A pale surface asks for the artwork's colours as the client drew
   them; the control panel is the only one, and dashboard.css applies this there.
   The tag plate keeps `--accent` on both, which is the whole reason it was
   recoloured from the master's own lime: one lime on the page, not two. */
.mark--paper {
  --lg-one: #0d5c2e;
  --lg-vill: #2fa04a;
  --lg-tagink: #0d5c2e;
}
@media (prefers-reduced-motion: reduce) {
  .mark-glyph { transition: none; }
}
.mark-sub { display: block; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: color-mix(in oklab, #fff, transparent 42%); }

.tabs { margin-left: auto; display: flex; align-items: center; gap: 0.2rem; }
.tab-item { position: relative; }
.tab {
  display: inline-block;
  padding: 0.55rem 0.7rem;
  font-size: 1.02rem;
  font-weight: 700;
  white-space: nowrap;
  color: #fff;
  text-decoration: none;
  border-radius: var(--r-sm);
  transition: color 0.16s var(--ease);
}
.tab:hover { color: var(--accent); text-decoration: none; }
.tab.is-here { color: var(--accent); box-shadow: inset 0 -2px 0 var(--accent); }

.subtabs {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  min-width: 16.5rem;
  background: var(--white);
  box-shadow: var(--shadow-lg);
  border-radius: var(--r);
  padding: 0.4rem;
  opacity: 0;
  visibility: hidden;
  translate: 0 6px;
  transition: opacity 0.16s var(--ease), translate 0.16s var(--ease), visibility 0.16s;
}
.tab-item:hover .subtabs, .tab-item:focus-within .subtabs { opacity: 1; visibility: visible; translate: 0 0; }
.subtabs a {
  display: block;
  padding: 0.55rem 0.7rem;
  color: var(--body);
  font-size: 0.94rem;
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--r-sm);
}
.subtabs a:hover { background: var(--paper); color: var(--ink); text-decoration: none; }

.tabs-toggle {
  display: none;
  margin-left: auto;
  width: 2.8rem;
  height: 2.8rem;
  padding: 0;
  background: transparent;
  color: #fff;
  border: 1.5px solid var(--line-dark);
  border-radius: var(--r-sm);
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.tabs-toggle svg { width: 1.1rem; height: 1.1rem; }

/* --- Actions ----------------------------------------------------------------- */

.act {
  white-space: nowrap;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.8rem 1.4rem;
  font-family: var(--text);
  font-size: 0.98rem;
  font-weight: 700;
  line-height: 1.2;
  cursor: pointer;
  border: 0;
  border-radius: var(--r-pill);
  text-decoration: none;
  transition: background 0.16s var(--ease), color 0.16s var(--ease), box-shadow 0.16s var(--ease), translate 0.16s var(--ease);
}
.act:hover { text-decoration: none; translate: 0 -1px; }
.act:disabled, .act[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

/* The reference's pill CTA with its circular arrow badge. */
.act-press {
  background: var(--white);
  color: var(--ink);
  padding-right: 0.45rem;
  box-shadow: var(--shadow-sm);
}
.act-press::after {
  content: "";
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2314201a' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13M13 6l6 6-6 6'/%3E%3C/svg%3E") center / 1rem 1rem no-repeat;
  transition: translate 0.16s var(--ease);
}
.act-press:hover { background: var(--white); color: var(--ink); box-shadow: var(--shadow); }
.act-press:hover::after { translate: 2px 0; }

.act-green { background: var(--accent); color: var(--ink); }
.act-green:hover { background: #d3f083; color: var(--ink); }

.act-line {
  background: transparent;
  color: var(--ink);
  /* 48% and no lighter: the ring is the only thing that makes an outline button
     read as a button, and it has to clear the 3:1 floor for non-text UI
     boundaries. The old `--line` hairline was 1.37:1 on white — decoration, not
     an affordance. */
  box-shadow: inset 0 0 0 1.5px color-mix(in oklab, var(--ink), transparent 48%);
}
.act-line:hover { box-shadow: inset 0 0 0 1.5px var(--ink); color: var(--ink); }
.on-ink .act-line, .leaf--green .act-line, .leaf--ink .act-line,
.arrivals .act-line, .leaf-top .act-line { color: #fff; box-shadow: inset 0 0 0 1.5px var(--line-dark); }
.on-ink .act-line:hover, .leaf--green .act-line:hover, .leaf--ink .act-line:hover,
.arrivals .act-line:hover, .leaf-top .act-line:hover { box-shadow: inset 0 0 0 1.5px var(--accent); color: var(--accent); }

.act-dark { background: var(--ground); color: #fff; }
.act-dark:hover { background: var(--ground-3); color: #fff; }

.act-quiet {
  background: none;
  color: var(--accent-deep);
  padding: 0.3rem 0;
  border-radius: 0;
  font-weight: 700;
  box-shadow: inset 0 -1.5px 0 currentColor;
}
.act-quiet:hover { color: var(--ink); translate: none; }
/* A quiet link for a destructive action. Not `--accent`: on the white panel
   this sits on, citrus text is 1.39:1. */
.act-quiet--warn { color: #a8332e; }
.act-quiet--warn:hover { color: #7c2521; }
.on-ink .act-quiet, .leaf--green .act-quiet, .leaf--ink .act-quiet,
.arrivals .act-quiet, .leaf-top .act-quiet { color: var(--accent); }
.on-ink .act-quiet:hover, .leaf--green .act-quiet:hover, .leaf--ink .act-quiet:hover { color: #fff; }

/* --- Light surfaces on a deep ground ---------------------------------------
   `.float-card`, `.panel`, `.record` and `.tile` all paint themselves white and
   any of them can sit on a deep section; `.on-paper` is the opt-in hook for
   anything else. The on-dark variants above key off the *section*, not the surface
   the control is actually on, so without this a button inside one of them takes
   the dark reading on a white card — citrus or white text on white.

   `.record` is the one that bit in practice. The news, events and resources
   index sections are deep grounds while the projects index is white, so the
   identical `.act-quiet` in the three card partials rendered "Explore project"
   correctly at 5:1 and "Read it" and "See the event" as citrus on white at
   1.4:1. The markup was never the difference; the ground was.

   Add any new component that sets its own light background to this list, or
   give it `.on-paper`. */
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) .act-line {
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px color-mix(in oklab, var(--ink), transparent 48%);
}
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) .act-line:hover {
  color: var(--ink);
  box-shadow: inset 0 0 0 1.5px var(--ink);
}
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) .act-quiet { color: var(--accent-deep); }
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) .act-quiet:hover { color: var(--ink); }
/* A prose link inside a light card takes the pale-ground link colour. This is
   the same leak the buttons had: the deep-ground rule is `:where(...) a`, weak
   on purpose so components win, but a bare `<a>` has no class to win with — so
   "Sign in" and "Create one" came out citrus on the white sign-in card at
   1.39:1.

   `a:where(:not(.act))` rather than `a:not(.act)` on purpose. `:where()`
   contributes no specificity, so this lands at (0,1,1): heavy enough to beat
   the deep-ground rule, light enough that `.record-title a` and the rest still
   win, and buttons are excluded outright rather than out-weighed. */
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) a:where(:not(.act)) {
  color: var(--accent-deep);
  text-decoration-color: color-mix(in oklab, var(--accent-deep), transparent 55%);
}
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) a:where(:not(.act)):hover { color: var(--ink); }
/* A heading inside a light card is ink, not the section's accent. */
:is(.on-paper, .float-card, .panel, .record, .tile, .sheet-form) :is(h1, h2, h3, h4) { color: var(--ink); }

.act-warn { background: #a8332e; color: #fff; }
.act-warn:hover { background: #8a2a26; color: #fff; }

.act-sm { padding: 0.5rem 1rem; font-size: 0.88rem; }
.act-sm.act-press { padding-right: 0.35rem; }
.act-sm.act-press::after { width: 1.6rem; height: 1.6rem; background-size: 0.85rem 0.85rem; }
.act-row { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: center; }

/* --- Hero --------------------------------------------------------------------- */

.arrivals {
  position: relative;
  background: var(--ground);
  color: #fff;
  min-height: clamp(30rem, 78vh, 46rem);
  display: flex;
  align-items: center;
  margin-top: calc(var(--bar) * -1);
  padding: calc(var(--bar) + 3.5rem) 0 clamp(4rem, 8vh, 6rem);
  overflow: hidden;
  isolation: isolate;
}
.arrivals-media { position: absolute; inset: 0; z-index: -2; }
/* Page-head bands are wide and short, so a centred crop lands on torsos.
   Biasing the crop upward keeps faces and horizons in frame.

   The desaturate-and-darken is not decoration. The home hero gets two layers —
   a colour blend over the tiles and then a scrim — and page heads only had the
   scrim, so a bright photograph washed the lede and the detail list out to
   around 2.5:1. This filter is the page-head equivalent of the wall's blend:
   it pulls the photograph toward the ground colour before the scrim goes over
   it, which is what makes the small type survive whatever gets uploaded. */
.arrivals-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  border-radius: 0;
  filter: saturate(0.5) brightness(0.78);
}
/* The scrim: identical role to the reference's, so type stays legible over
   whatever photograph the client eventually uploads. */
.arrivals-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(14, 42, 34, 0.8) 0%, rgba(14, 42, 34, 0.72) 45%, rgba(14, 42, 34, 0.9) 100%);
}

/* --- The photo wall ------------------------------------------------------------
   The home hero's background is a wall of the foundation's photographs that
   drifts left forever. Three layers make that survivable behind a headline: the
   drift itself has to stay slow enough to read as weather rather than motion, a
   colour blend pulls twenty-odd unrelated frames onto one hue, and a scrim
   carries the text contrast. Take any of them away and the hero becomes a
   sliding stock-photo patchwork with white type floating on it. */
.wall {
  --tile: clamp(6.5rem, 10vw, 16rem);
  /* One duration for every row: the wall travels as a single sheet. */
  --wall-dur: 64s;
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background: var(--ground);
  isolation: isolate;
  display: flex;
  flex-direction: column;
}
/* Rows share the hero's height rather than claiming a fixed one, so seven of
   them cover every viewport exactly — no bare ground at the bottom of a tall
   phone, no wasted rows animating off-screen on a short desktop. */
.wall-row {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  width: max-content;
  animation: wall-drift var(--wall-dur) linear infinite;
}
.wall-run { display: flex; flex: 0 0 auto; }
.wall-run img {
  display: block;
  width: var(--tile);
  height: 100%;
  object-fit: cover;
  border-radius: 0;
  margin: 0 3px 3px 0;
}
/* Exactly half the row is one full run of tiles, so the duplicate lands where
   the original started and the loop has no seam. The 3px tile margins are
   margins rather than a flex `gap` for the same reason: a gap between the two
   runs would put the halves out by a pixel and the seam would show. */
@keyframes wall-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .wall-row { animation: none; }
}
/* Both overlays are positioned so they paint above the rows; ::before is the
   first child and would otherwise sit underneath them. */
.wall::before,
.wall::after { content: ""; position: absolute; inset: 0; }
/* Duotone: force every photograph toward the ground green so twenty-odd
   unrelated frames read as one field instead of a stock-photo patchwork. */
.wall::before {
  z-index: 1;
  background: var(--ground);
  mix-blend-mode: color;
  opacity: 0.7;
}
/* The scrim: the headline sits on this, so it carries the contrast. */
.wall::after {
  z-index: 2;
  background: linear-gradient(180deg, rgba(14, 42, 34, 0.78) 0%, rgba(14, 42, 34, 0.66) 42%, rgba(14, 42, 34, 0.9) 100%);
}
/* Safari and Firefox both honour mix-blend-mode, but if a browser drops it the
   photographs would come through at full saturation. The fallback darkens
   instead of tinting — less handsome, still legible. */
@supports not (mix-blend-mode: color) {
  .wall::before { mix-blend-mode: normal; opacity: 0.55; }
}
}
.arrivals .page { position: relative; text-align: center; }
.arrivals h1 {
  color: #fff;
  font-size: clamp(2rem, 4.4vw, 3.5rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  line-height: 1.06;
  margin: 0 auto 0.55em;
  max-width: 24ch;
}
.arrivals-tagline {
  font-size: clamp(1.05rem, 1.8vw, 1.35rem);
  font-weight: 500;
  line-height: 1.55;
  color: color-mix(in oklab, #fff, transparent 12%);
  margin: 0 auto 2rem;
  max-width: 56ch;
}
.arrivals-actions { display: flex; flex-wrap: wrap; gap: 0.85rem; justify-content: center; }

/* Interior page heads: same architecture, shorter.

   Both the hero and the page heads carry `on-ink` in the markup. They are dark
   grounds like `.leaf--ink` is, and without it the shared on-dark rules never
   reached them: `.dl-code` and `.code` kept their pale-ground colours and came
   out dark green on dark green. The explicit `.leaf-top`/`.arrivals` rules below
   are declared after the on-ink block, so they still win where they disagree —
   which is how the h1 stays white instead of turning accent. */
.leaf-top {
  position: relative;
  background: var(--ground);
  color: #fff;
  margin-top: calc(var(--bar) * -1);
  padding: calc(var(--bar) + 2.5rem) 0 clamp(3rem, 6vw, 4.5rem);
  overflow: hidden;
  isolation: isolate;
}
.leaf-top h1 { color: #fff; max-width: 18ch; }
.leaf-top .lede { color: color-mix(in oklab, #fff, transparent 12%); max-width: 52ch; }
.leaf-top .dl-code { margin-top: 1.75rem; }
.leaf-top .section-label { margin-bottom: 1rem; }

/* --- Pillars: the reference's hairline-divided three-column row --------------- */

.pillars {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  margin-top: clamp(2rem, 4vw, 3rem);
}
.pillar { display: flex; flex-direction: column; align-items: flex-start; padding: 0 clamp(1.25rem, 2.5vw, 2.25rem); border-left: 1px solid var(--line-dark); }
.pillar:first-child { padding-left: 0; border-left: 0; }
.pillar h3 { color: var(--accent); margin-bottom: 1.4rem; font-size: 1.22rem; }
.pillar p { font-size: 0.97rem; margin-bottom: 1.1rem; }
.pillar .act-quiet { margin-top: auto; }
/* Fixed height rather than a ratio: the first pillar runs to the page edge and
   is therefore wider than its neighbours, and a shared ratio would leave the
   three headings sitting on different lines. */
.pillar-shot { width: 100%; height: clamp(8.5rem, 12vw, 11rem); margin-bottom: 1.35rem; }

/* --- Floating white card ------------------------------------------------------ */

.float-card {
  background: var(--white);
  border-radius: var(--r);
  padding: clamp(1.75rem, 3vw, 2.25rem);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: flex-start;
}
.float-card h3 { font-size: clamp(1.4rem, 2.2vw, 1.85rem); font-weight: 800; color: var(--ink); margin: 0; line-height: 1.14; }
.float-card p { color: var(--body); font-size: 0.97rem; margin: 0; }
.float-card .act { margin-top: auto; }

/* --- Photographs ---------------------------------------------------------------
   Every photograph is the client's own, served as a WebP derivative through the
   `photo` template tag. `.shot` is the frame: a declared ratio so a row of them
   never goes ragged, clipped overflow so object-fit crops instead of squashing,
   and a ground-coloured backdrop so a slow image loads as part of the design
   rather than as a white hole. */
.shot { position: relative; overflow: hidden; border-radius: var(--r); background: var(--ground-2); }
.shot img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.shot--wide { aspect-ratio: 16 / 9; }
.shot--photo { aspect-ratio: 4 / 3; }
.shot--tall { aspect-ratio: 4 / 5; }
.shot--square { aspect-ratio: 1; }
/* Full-column bands are sized by height, not by ratio. A ratio cannot keep one
   of these in proportion — the column keeps getting wider, so the photograph
   keeps getting taller, and at 1200px a 21:8 band was 450px of picture standing
   in front of the section it is meant to introduce. Capping the height while a
   ratio is still set is worse again: the browser holds the ratio and shrinks the
   width instead, so the band stops filling its column. A declared height and
   `object-fit: cover` crop instead of scaling, which is what a band should do. */
.shot--band { height: clamp(11rem, 21vw, 19rem); }

/* A section carrying a photograph behind its own text. The scrim comes from
   .arrivals-media::after, which is why this only ever pairs with a dark leaf. */
.has-shot { position: relative; overflow: hidden; isolation: isolate; }

/* A photograph with the card riding up over its lower edge — the one place the
   home page lets two planes overlap, so it stays an accent rather than a tic. */
.media-stack { display: grid; }
.media-stack .float-card { position: relative; z-index: 1; margin: -3.5rem clamp(0.75rem, 2vw, 1.75rem) 0; }

/* Sub-blocks inside one section, split by hairline. The home page's opening
   band uses them so projects, events and news read as one answer to "what are
   you working on" instead of three sections competing for the same visitor. */
.band + .band {
  margin-top: clamp(2.5rem, 5vw, 3.75rem);
  padding-top: clamp(2.5rem, 5vw, 3.75rem);
  border-top: 1px solid var(--line);
}
.on-ink .band + .band, .leaf--green .band + .band, .leaf--ink .band + .band { border-top-color: var(--line-dark); }
.band-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem 1.5rem;
  margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem);
}
.band-head h3 {
  font-size: clamp(1.3rem, 2.4vw, 1.85rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.12;
  color: var(--ink);
  margin: 0;
}
.on-ink .band-head h3, .leaf--green .band-head h3, .leaf--ink .band-head h3 { color: var(--accent); }

/* Focus areas as a divided list: no numbering on an unordered set, and no
   grid of identical number-plus-heading cards. */
.area-list { display: grid; gap: 0; }
.area-row {
  display: grid;
  grid-template-columns: clamp(5rem, 9vw, 9rem) minmax(0, 0.85fr) minmax(0, 1.3fr);
  gap: 1rem clamp(1.25rem, 3vw, 2.25rem);
  align-items: center;
  padding: 1.5rem 0;
  border-top: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  transition: color 0.16s var(--ease);
}
.area-list .area-row:last-child { border-bottom: 1px solid var(--line); }
.area-name { font-size: clamp(1.2rem, 2vw, 1.6rem); font-weight: 800; letter-spacing: -0.018em; color: var(--ink); line-height: 1.14; }
.area-summary { font-size: 0.98rem; color: var(--body); max-width: 62ch; }
.area-row:hover { text-decoration: none; }
.area-row:hover .area-name { color: var(--accent-deep); }
.area-shot img { transition: scale 0.5s var(--ease); }
.area-row:hover .area-shot img { scale: 1.06; }
@media (prefers-reduced-motion: reduce) {
  .area-shot img { transition: none; }
  .area-row:hover .area-shot img { scale: 1; }
}
.on-ink .area-row, .leaf--green .area-row, .leaf--ink .area-row { border-color: var(--line-dark); }
.on-ink .area-name, .leaf--green .area-name, .leaf--ink .area-name { color: var(--accent); }

/* --- Jump band -----------------------------------------------------------------
   The focus-area index on Our Work. It used to sit in a bare `.page` div with
   padding on one side only, between the page head and the first section, which
   is exactly why it read as an orphan. Given a ground, a closing hairline and a
   label set beside the list rather than stacked above it, it reads as the end of
   the page head instead. */
.jump { background: var(--white); border-bottom: 1px solid var(--line); }
.jump .page {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem 1.25rem;
  padding-top: clamp(1.1rem, 2vw, 1.5rem);
  padding-bottom: clamp(1.1rem, 2vw, 1.5rem);
}
.jump-list { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* --- Records: cards ------------------------------------------------------------ */

.records { display: grid; gap: clamp(1.4rem, 2.4vw, 1.9rem); }
.records--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.records--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.records--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.record {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.18s var(--ease), translate 0.18s var(--ease);
}
.record:hover { box-shadow: var(--shadow); translate: 0 -3px; }

.record-face { position: relative; aspect-ratio: 16 / 10; overflow: hidden; }
.record-face img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.record-body { display: flex; flex-direction: column; gap: 0.55rem; padding: 1.3rem 1.45rem 1.55rem; flex: 1; }
.record-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.9rem; }
.record-title { font-size: 1.16rem; font-weight: 800; margin: 0; letter-spacing: -0.015em; }
.record-title a { color: var(--ink); text-decoration: none; }
.record-title a:hover { color: var(--accent-deep); text-decoration: none; }
.record-body > p { margin: 0; font-size: 0.96rem; color: var(--body); }
.record-foot { margin-top: auto; padding-top: 1rem; display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.record-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.record-foot .act, .record-foot a { position: relative; z-index: 2; }

.records--3 > .record:only-child, .records--2 > .record:only-child { grid-column: 1 / -1; flex-direction: row; }
.records--3 > .record:only-child .record-face, .records--2 > .record:only-child .record-face { flex: 0 0 38%; aspect-ratio: auto; }
.records--3 > .record:only-child .record-body, .records--2 > .record:only-child .record-body { justify-content: center; padding: 2.25rem 2.4rem; }
.records--3 > .record:only-child .record-body > p, .records--2 > .record:only-child .record-body > p { max-width: 62ch; }

/* The drawn block that stands where a photograph will go. */
.impression {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: var(--ground);
  overflow: hidden;
}
.impression svg { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.55; }
.impression--magenta, .impression--ink { background: var(--ground-2); }
.impression--violet { background: var(--ground-3); }
.impression--amber { background: var(--ground-2); }
.impression-ring { position: relative; display: grid; place-items: center; gap: 0.2rem; color: var(--accent); }
.impression-word { font-size: 2.6rem; font-weight: 900; line-height: 1; }
.impression-code { font-size: 0.66rem; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; opacity: 0.8; }

/* --- Tiles: the home page's record card ----------------------------------------
   Photograph, then title, then a line of summary — small enough that a whole
   band fits in one row, so a visitor takes in everything the foundation is
   doing before deciding to scroll.

   The three record types are given different shapes rather than a single card
   repeated three times: a different photo ratio, and one square corner in a
   different place. The square corner is not arbitrary — the logo's bubble is
   two offset blocks with exactly one hard corner where they step, and these
   carry the same silhouette. Projects are documentary 4:3, events are wide
   because an event is a date before it is a picture, news is editorial square. */
/* A flex row rather than a grid: a band with one published record should show
   one card at a sensible width, not one card and three empty columns. Four fit
   across a full page; fewer simply take the room they need. */
.tiles { display: flex; flex-wrap: wrap; gap: clamp(0.9rem, 1.6vw, 1.35rem); }
.tile {
  flex: 1 1 14rem;
  max-width: 22rem;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
  transition: box-shadow 0.2s var(--ease), translate 0.2s var(--ease);
}
.tile:hover { text-decoration: none; box-shadow: var(--shadow); translate: 0 -3px; }
.tile--project { border-bottom-left-radius: 0; }
.tile--event { border-top-right-radius: 0; }
.tile--news { border-bottom-right-radius: 0; }
.tile-face { position: relative; display: block; overflow: hidden; background: var(--ground-2); }
.tile-face img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.tile--project .tile-face { aspect-ratio: 4 / 3; }
.tile--event .tile-face { aspect-ratio: 21 / 9; }
.tile--news .tile-face { aspect-ratio: 1; }
.tile-body { display: grid; gap: 0.4rem; padding: 0.95rem 1.1rem 1.2rem; }
.tile-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem 0.7rem; }
.tile-flag { position: absolute; z-index: 1; left: 0.6rem; top: 0.6rem; }
.tile-title {
  font-size: 1.04rem;
  font-weight: 800;
  line-height: 1.22;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-wrap: pretty;
  transition: color 0.16s var(--ease);
}
.tile:hover .tile-title { color: var(--accent-deep); }
.tile-text { font-size: 0.91rem; line-height: 1.5; color: var(--body); }
@media (prefers-reduced-motion: reduce) {
  .tile, .tile-title { transition: none; }
  .tile:hover { translate: none; }
}

/* --- Entries ------------------------------------------------------------------- */

.entries { display: grid; gap: 0; }
.entry {
  position: relative;
  display: grid;
  gap: 0.4rem;
  padding: 1.7rem 0;
  align-items: start;
  text-decoration: none;
  color: inherit;
  border-top: 1px solid var(--line);
}
.entries .entry:first-child { border-top: 0; }
.entry:hover { text-decoration: none; }
.entry-title { font-size: clamp(1.25rem, 2.1vw, 1.65rem); font-weight: 800; color: var(--ink); margin: 0 0 0.35rem; line-height: 1.14; letter-spacing: -0.018em; transition: color 0.16s var(--ease); }
.on-ink .entry-title, .leaf--green .entry-title, .leaf--ink .entry-title { color: var(--accent); }
.entry:hover .entry-title { color: var(--accent-deep); }
.on-ink .entry:hover .entry-title, .leaf--green .entry:hover .entry-title, .leaf--ink .entry:hover .entry-title { color: #fff; }
.entry p { margin: 0; max-width: 60ch; }
.on-ink .entry, .leaf--green .entry, .leaf--ink .entry { border-top-color: var(--line-dark); }

/* --- Notes --------------------------------------------------------------------- */

.notes { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.75rem; }
.notes li { position: relative; padding-left: 1.6rem; }
.notes li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--accent-deep);
}
.on-ink .notes li::before, .leaf--green .notes li::before, .leaf--ink .notes li::before { background: var(--accent); }

/* --- Tags ---------------------------------------------------------------------- */

.tickets { display: flex; flex-wrap: wrap; gap: 0.55rem; }
.ticket {
  display: inline-flex;
  align-items: center;
  padding: 0.42rem 0.9rem;
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--line);
  color: var(--body);
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--r-pill);
  transition: box-shadow 0.16s var(--ease), background 0.16s var(--ease), color 0.16s var(--ease);
}
a.ticket:hover { box-shadow: inset 0 0 0 1.5px var(--ink); color: var(--ink); text-decoration: none; }
.ticket.is-on { background: var(--ground); color: #fff; box-shadow: none; }
a.ticket.is-on:hover { background: var(--ground-3); color: #fff; }
.on-ink .ticket, .leaf--green .ticket, .leaf--ink .ticket { color: #fff; box-shadow: inset 0 0 0 1.5px var(--line-dark); }
.on-ink a.ticket:hover, .leaf--green a.ticket:hover, .leaf--ink a.ticket:hover { box-shadow: inset 0 0 0 1.5px var(--accent); color: var(--accent); }
.on-ink .ticket.is-on, .leaf--green .ticket.is-on, .leaf--ink .ticket.is-on { background: var(--accent); color: var(--ink); box-shadow: none; }

/* --- Counts -------------------------------------------------------------------- */

.counts { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 2rem 1.75rem; }
.count { position: relative; padding-top: 1.1rem; border-top: 2px solid var(--accent); }
.count-value { font-size: clamp(1.8rem, 3vw, 2.5rem); font-weight: 900; line-height: 1; color: var(--accent); letter-spacing: -0.03em; }
.count h3 { font-size: 1rem; margin: 0.5rem 0 0.3rem; font-weight: 800; }
.count p { font-size: 0.92rem; margin: 0; }

/* --- Panels -------------------------------------------------------------------- */

.panel { background: var(--white); border-radius: var(--r); padding: 1.55rem 1.7rem; box-shadow: var(--shadow-sm); }
.panel + .panel { margin-top: 1.15rem; }
/* A panel's own heading is an h2 when the panel is a section of a page whose
   only other heading is the h1 — which is most of them. The level is semantic;
   the size is the panel's, not the document's h2 scale. */
.panel :is(h2, h3) {
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.08;
  margin-bottom: 0.85rem;
}
.panel--amber { background: var(--accent); color: var(--ink); }
.panel--amber :is(h2, h3) { color: var(--ink); }
.panel--amber a { color: var(--ink); }
/* `.code` carries `--muted`, which is 3.97:1 on the citrus this panel is
   painted in. On an accent ground the meta line takes ink like everything else,
   held back by weight rather than by colour. */
.panel--amber .code { color: color-mix(in oklab, var(--ink), transparent 22%); }
.panel--ink { background: var(--ground); color: color-mix(in oklab, #fff, transparent 16%); }
.panel--ink h3 { color: var(--accent); }

.sheet-form { position: relative; background: var(--white); border-radius: var(--r-lg); padding: clamp(1.85rem, 3.2vw, 2.6rem); box-shadow: var(--shadow-lg); }

/* --- Forms --------------------------------------------------------------------- */

.form-row { margin-bottom: 1.2rem; }
.form-row > label { display: block; font-size: 0.85rem; font-weight: 700; color: var(--ink); margin-bottom: 0.45rem; }
.field-req { color: var(--accent-deep); margin-left: 0.15rem; }

.form-control {
  width: 100%;
  padding: 0.75rem 0.95rem;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--white);
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease);
}
.form-control::placeholder { color: var(--muted); }
.form-control:hover { border-color: color-mix(in oklab, var(--ink), transparent 60%); }
.form-control:focus { outline: none; border-color: var(--ground); box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 45%); }
textarea.form-control { resize: vertical; min-height: 7.5rem; line-height: 1.55; }
select.form-control {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ground) 50%), linear-gradient(135deg, var(--ground) 50%, transparent 50%);
  background-position: calc(100% - 1.2rem) 1.2rem, calc(100% - 0.85rem) 1.2rem;
  background-size: 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.4rem;
}
select[multiple].form-control, .form-multiselect { background-image: none; padding-right: 1rem; min-height: 8rem; }
input[type="file"].form-control { padding: 0.55rem 0.8rem; font-size: 0.9rem; }
input[type="file"].form-control::file-selector-button {
  font: inherit; font-size: 0.85rem; font-weight: 700;
  margin-right: 0.8rem; padding: 0.4rem 0.9rem;
  background: var(--ground); color: #fff; border: 0; border-radius: var(--r-pill); cursor: pointer;
}
input[type="file"].form-control::file-selector-button:hover { background: var(--ground-3); }

.field-help, .form-help { font-size: 0.86rem; color: var(--muted); margin-top: 0.4rem; }
.field-error, .form-errors { font-size: 0.87rem; color: #9a2f2a; margin-top: 0.4rem; font-weight: 600; }

.form-check, .check { display: flex; align-items: flex-start; gap: 0.6rem; }
.form-check-input { width: 1.35rem; height: 1.35rem; margin-top: 0.08rem; accent-color: var(--ground); flex-shrink: 0; }
/* The label is the larger equivalent target and toggles the box, so the row is
   what a finger actually aims at. Padding rather than a min-height on a flex
   box: these labels carry consent copy that wraps, and centring a wrapped label
   would pull it off the checkbox it belongs to. */
.form-check label, .check label { padding: 0.15rem 0; }
.form-check label, .check label { font-size: 0.98rem; text-transform: none; letter-spacing: 0; color: var(--body); margin: 0; font-weight: 400; }
.form-check-list, .check-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem; }
.form-check-list li, .check-list li { display: flex; align-items: center; gap: 0.55rem; }

/* --- Tick lists (focus areas, and any other multi-select) ---------------------- */

/* The class reaches both the wrapper and every option input, so each role is
   written out separately rather than fought over. */
/* --- Linear scale ----------------------------------------------------------
   A row of radios read left to right, with the two end labels outside it. The
   points share the row equally and each carries its number above the control,
   so the numbers line up whatever the range and the label is the hit target.

   The fieldset is reset because a UA fieldset brings its own border, padding
   and an inline-block width that will not fill the column. */
.form-scale { border: 0; padding: 0; margin-inline: 0; min-width: 0; }
.form-scale > legend {
  display: block;
  padding: 0;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 0.45rem;
}
.scale {
  display: flex;
  align-items: center;
  gap: 0.5rem 1.1rem;
  flex-wrap: wrap;
  padding: 0.7rem 0.9rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--white);
}
.scale-end {
  font-size: 0.9rem;
  color: var(--body);
  /* The ends caption the row; they must not compete with the numbers in it. */
  flex-shrink: 0;
  max-width: 11rem;
}
.scale-points {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.25rem;
  flex: 1 1 14rem;
  min-width: 0;
  /* An eleven-point scale on a narrow phone is wider than the column. It
     scrolls inside itself; the page never scrolls sideways. */
  overflow-x: auto;
  padding: 0.15rem 0.2rem 0.25rem;
}
.scale-point {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  flex: 1 0 auto;
  min-width: 2.35rem;
  padding: 0.15rem 0;
  font-weight: 400;
  color: var(--body);
  cursor: pointer;
}
.scale-num { font-size: 0.9rem; font-variant-numeric: tabular-nums; line-height: 1; }
.scale-point:hover { color: var(--ink); }
.scale-point:hover .scale-num { font-weight: 700; }
input.scale-input {
  width: 1.35rem;
  height: 1.35rem;
  margin: 0;
  accent-color: var(--ground);
  cursor: pointer;
}
/* The label is the hit target, so the ring belongs on the label, not the dot. */
.scale-point:has(.scale-input:focus-visible) {
  outline: 3px solid var(--accent-deep);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
.scale-point:has(.scale-input:focus-visible) .scale-input { outline: none; }
.scale-point:has(.scale-input:checked) .scale-num { font-weight: 800; color: var(--ink); }

/* Below this the two ends cannot sit either side of a usable row of points, so
   the points take the full width and the ends drop underneath at each end. */
@media (max-width: 560px) {
  .scale { gap: 0.35rem; }
  .scale-points { order: -1; flex-basis: 100%; }
  .scale-end--high { margin-left: auto; text-align: right; }
}

div.check-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: 0.15rem 1.1rem;
  padding: 0.7rem 0.9rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--white);
}
div.check-grid label {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.3rem 0;
  font-size: 0.93rem;
  font-weight: 400;
  color: var(--body);
  cursor: pointer;
}
div.check-grid label:hover { color: var(--ink); }
input.check-grid {
  width: 1.05rem; height: 1.05rem; margin: 0;
  accent-color: var(--ground); flex-shrink: 0; cursor: pointer;
}

.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1.25rem; }
.form-grid .full { grid-column: 1 / -1; }

.code-input { letter-spacing: 0.35em; font-size: clamp(1.2rem, 4vw, 1.5rem); text-align: center; font-weight: 700; padding-left: 0.35em; }

/* --- Status badges -------------------------------------------------------------- */

.overprint {
  display: inline-flex;
  align-items: center;
  padding: 0.28rem 0.7rem;
  font-size: 0.71rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--accent);
  border-radius: var(--r-pill);
}
.overprint--live { background: var(--accent); color: var(--ink); }
.overprint--open { background: var(--ground); color: var(--accent); }
.overprint--done, .overprint--shut { background: var(--line); color: var(--body); }
.on-ink .overprint--done, .leaf--green .overprint--done,
.on-ink .overprint--shut, .leaf--green .overprint--shut { background: var(--line-dark); color: #fff; }

/* --- Notices -------------------------------------------------------------------- */

.notices { max-width: var(--max); margin: 1.25rem auto 0; padding: 0 1.75rem; display: grid; gap: 0.6rem; }
.notice {
  padding: 0.9rem 1.2rem;
  background: color-mix(in oklab, var(--accent), var(--paper) 55%);
  color: var(--ink);
  font-size: 0.96rem;
  font-weight: 500;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1.5px color-mix(in oklab, var(--accent-deep), transparent 72%);
}
.notice-error { background: #f7e3e0; color: #7d251f; box-shadow: inset 0 0 0 1.5px rgba(168, 51, 46, 0.28); }
.notice-warning { background: #f8eeda; color: #6f5412; box-shadow: inset 0 0 0 1.5px rgba(193, 148, 24, 0.3); }

/* --- Filters, paging, empty ------------------------------------------------------ */

.filter-bar { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: center; margin-bottom: 2.25rem; }
/* A tag row sits under the filter bar, or under a record's lede. */
.tag-row { margin-top: 1.5rem; }
.filter-bar + .tag-row { margin: -1.35rem 0 2.25rem; }
.filter-bar form { display: flex; gap: 0.55rem; flex: 1 1 16rem; }
.filter-bar .form-control { flex: 1; }

.paging { display: flex; gap: 0.5rem; justify-content: center; align-items: center; margin-top: 2.75rem; }
.paging a, .paging span { font-size: 0.85rem; font-weight: 700; padding: 0.55rem 1rem; text-decoration: none; border-radius: var(--r-pill); }
.paging a { color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--line); }
.paging a:hover { background: var(--white); text-decoration: none; }
.paging .current { color: var(--muted); }

.empty-state { padding: clamp(2.5rem, 5vw, 3.5rem) 1.75rem; text-align: center; border: 1.5px dashed var(--line); border-radius: var(--r-lg); }
.empty-mark { width: 3rem; height: 3rem; margin: 0 auto 1.1rem; border-radius: 50%; background: color-mix(in oklab, var(--accent), var(--paper) 45%); }
.empty-state h3 { font-size: 1.15rem; margin-bottom: 0.4rem; }
.empty-state p { font-size: 0.95rem; margin: 0 auto; max-width: 34ch; color: var(--muted); }
.on-ink .empty-state, .leaf--green .empty-state, .leaf--ink .empty-state { border-color: var(--line-dark); }
.on-ink .empty-state p, .leaf--green .empty-state p, .leaf--ink .empty-state p { color: color-mix(in oklab, #fff, transparent 34%); }
.on-ink .empty-mark, .leaf--green .empty-mark, .leaf--ink .empty-mark { background: var(--line-dark); }

/* --- Footer ---------------------------------------------------------------------- */

.colophon { background: var(--ground); color: color-mix(in oklab, #fff, transparent 28%); padding: clamp(3rem, 6vw, 4.5rem) 0 2rem; }
.colophon-head { color: var(--accent); font-size: 0.74rem; letter-spacing: 0.11em; text-transform: uppercase; font-weight: 800; margin-bottom: 1rem; }
.colophon a { color: color-mix(in oklab, #fff, transparent 28%); text-decoration: none; font-size: 0.96rem; font-weight: 500; }
.colophon a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 0.18em; }
.colophon .mark { color: #fff; }
.colophon .mark-glyph { height: 5rem; }
.colophon .code { color: color-mix(in oklab, #fff, transparent 44%); }
.colophon-grid { display: grid; grid-template-columns: 1.7fr repeat(3, 1fr); gap: 2.25rem; }
/* The footer link columns are navigation, not prose, so each row has to be a
   real target. Left as bare inline links they measured 19px tall — under the
   24px floor on every phone. The padding buys the height without opening the
   gaps up, so the column reads as tightly grouped as before. */
.colophon-links { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.15rem; }
.colophon-links a { display: inline-block; padding: 0.32rem 0; }
.colophon-base { margin-top: 2.75rem; padding-top: 1.4rem; display: flex; flex-wrap: wrap; gap: 0.75rem 1.5rem; justify-content: space-between; border-top: 1px solid var(--line-dark); }
.subscribe { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.8rem; }
.subscribe .form-control { flex: 1 1 9rem; background: rgba(255, 255, 255, 0.08); color: #fff; border-color: var(--line-dark); }
.subscribe .form-control::placeholder { color: color-mix(in oklab, #fff, transparent 46%); }
.subscribe .form-control:focus { background: rgba(255, 255, 255, 0.14); border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent), transparent 75%); }

/* --- Layout helpers --------------------------------------------------------------- */

.split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.75rem, 4vw, 3.5rem); }
.split--aside { grid-template-columns: minmax(0, 1.55fr) minmax(0, 0.9fr); align-items: start; }
.split--head { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); align-items: start; }
.split--media { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; }
.stack { display: grid; gap: 1.1rem; }
.center { text-align: center; }
.center .leaf-head, .center .lede { margin-left: auto; margin-right: auto; }
.center .act-row { justify-content: center; }

/* --- Motion ----------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .js-press .press { opacity: 0; translate: 0 1rem; }
  .js-press .press.is-struck { opacity: 1; translate: 0 0; transition: opacity 0.55s var(--ease), translate 0.55s var(--ease); }
  .js-press .press-set > * { opacity: 0; translate: 0 0.8rem; }
  .js-press .press-set.is-struck > * { opacity: 1; translate: 0 0; transition: opacity 0.5s var(--ease), translate 0.5s var(--ease); }
  .js-press .press-set.is-struck > *:nth-child(2) { transition-delay: 70ms; }
  .js-press .press-set.is-struck > *:nth-child(3) { transition-delay: 140ms; }
  .js-press .press-set.is-struck > *:nth-child(4) { transition-delay: 210ms; }
  .js-press .press-set.is-struck > *:nth-child(5) { transition-delay: 280ms; }
  .js-press .press-set.is-struck > *:nth-child(6) { transition-delay: 350ms; }
}

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

/* --- Responsive --------------------------------------------------------------------- */

@media (max-width: 1080px) {
  .head-split { grid-template-columns: 1fr; gap: 1rem; }
  .pillars { grid-template-columns: 1fr; gap: 2rem; }
  .pillar { padding: 0 0 0 1.25rem; border-left: 1px solid var(--line-dark); }
  .pillar:first-child { padding-left: 1.25rem; border-left: 1px solid var(--line-dark); }
  .records--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .records--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .split--aside, .split--head, .split--media { grid-template-columns: 1fr; }
  .colophon-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .records--3 > .record:only-child { grid-column: span 2; }
}

/* The tab row collapses at 1240. Measured against real Mulish advance widths
   rather than estimated: the eight tab labels at 1.02rem/700 with their 0.7rem
   padding come to 845px, plus 22px of gaps, plus 101px for the Join us pill
   with its arrow badge, plus the 139px wordmark and the 1.25rem gap beside it
   — 1127px of content, so 1183px of viewport once the 56px gutters are added.
   The page itself stops growing at 1240, where it offers 1184px of content, so
   the breakpoint sits exactly where the row runs out of room: one pixel of
   slack below it, 57px at full width, and nothing above 1240 gets tighter.
   A navigation that does not fit should become the menu rather than shave its
   own hit targets — that trades hit target for density and is the wrong way
   round. Re-measure if a tab is added or renamed, if the tab size changes, or
   if the lockup's height changes (its width follows at 2.18x). The label
   widths came from `.cache/fonts/mulish.ttf` through fontTools; scripts using
   a substitute face over-estimate Mulish by a few percent. */
@media (max-width: 1240px) {
  .tabs-toggle { display: inline-flex; }
  .tabs {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--ground);
    padding: 0.75rem 1.75rem 1.5rem;
    box-shadow: var(--shadow);
    max-height: calc(100dvh - 5rem);
    overflow-y: auto;
  }
  .tabs.is-open { display: flex; }
  .masthead { background: var(--ground); }
  /* Same size as the desktop tab now, but stated rather than inherited: in
     the menu this is a full-width touch target, and it should not shrink
     if the desktop row is ever tuned down again. */
  .tab { padding: 0.7rem 0.5rem; font-size: 1.02rem; }
  .subtabs {
    position: static; opacity: 1; visibility: visible; translate: 0 0;
    box-shadow: none; background: transparent; padding: 0 0 0.4rem 0.85rem; min-width: 0;
  }
  .subtabs a { padding: 0.5rem; font-size: 0.95rem; color: color-mix(in oklab, #fff, transparent 26%); }
  .subtabs a:hover { background: transparent; color: var(--accent); }
  .tabs .act { margin-top: 0.85rem; justify-content: center; }
  /* Less zoom on a phone: at full scale the lockup crowds the menu button. */
  .masthead .mark-glyph { transform: scale(1.08); }
  .arrivals, .leaf-top { margin-top: 0; padding-top: clamp(3rem, 8vw, 5rem); }
}

@media (max-width: 680px) {
  body { font-size: 1rem; }
  .records--2, .records--3, .records--4 { grid-template-columns: 1fr; }
  .records--3 > .record:only-child { grid-column: auto; flex-direction: column; }
  .records--3 > .record:only-child .record-face { aspect-ratio: 16 / 10; }
  .records--3 > .record:only-child .record-body { padding: 1.3rem 1.45rem 1.55rem; }
  .split { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .colophon-grid { grid-template-columns: 1fr; gap: 1.75rem; }
  .counts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tile { max-width: none; }
  .filter-bar form { flex: 1 1 100%; }
  .utility .page { justify-content: center; gap: 1rem; font-size: 0.78rem; }
  /* Thumbnail beside the name, summary on its own line beneath both. */
  .area-row { grid-template-columns: clamp(4rem, 19vw, 6rem) minmax(0, 1fr); gap: 0.8rem 1.1rem; }
  .area-summary { grid-column: 1 / -1; }
  .media-stack .float-card { margin-inline: clamp(0.5rem, 3vw, 1.25rem); }
}
