/* Avery Hill · C11 split stage
   The model owns the left column and is never drawn over. The reading column
   owns the right and scrolls independently. On narrow screens the stage becomes
   a fixed band at the top and the reading column scrolls under it, which keeps
   the same contract: the two never overlap. */

:root {
  --ink: #F3EEE1;          /* the stage void, matched to the model's own DAY clear colour */
  --forest: #0F342E;
  --forest-lift: #16443B;
  --border: #2B5449;
  --cream: #FBF6EB;
  /* Measured against BOTH grounds, --forest and the lighter --forest-lift that
     panels and cards use, because the lighter one is the worst case and is what
     the reading column actually sits on.
       --body       7.31 on lift, 9.06 on forest   AAA
       --sage       7.31 on lift, 9.06 on forest   AAA
       --muted      7.04 on forest                 AAA on forest only
       --brick-lift 7.02 on lift, 8.71 on forest   AAA
     --muted is the one that cannot reach AAA on the lighter ground without
     becoming --body exactly, so it is a FOREST-ONLY text colour and small text
     on a lifted panel uses --sage instead. */
  --body: #C8D7CE;
  --muted: #ADBFB7;
  --sage: #BDDACC;
  --brick: #C25A42;
  /* The fill under CREAM text. #C25A42 gives 4.03:1, which is not AA at
     body size let alone AAA; this measures 7.32:1. --brick stays the
     non-text fill it always was. */
  --brick-solid: #843C2B;
  /* The same terracotta, lifted for TEXT on the dark ground. --brick itself is
     3.12:1 against --forest, which fails AA below 18.66px bold, so it is a fill
     colour here and not a text colour. This one measures 4.59:1. */
  /* Found by searching lightness at FULL saturation rather than simply
     lightening: the naive lift lands on #F2C6BB, a washed pink, where
     holding saturation at 1.0 keeps the terracotta and still clears the
     bar. 7.02 on the lifted ground, 8.71 on forest. */
  --brick-lift: #FFC1B1;
  /* The original #E07A5F, kept for LARGE display type only (24px, or 18.66px
     bold), where AAA asks 4.5:1 rather than 7:1. Full AAA for terracotta at
     body size lands on a pale pink that is no longer the brand's colour, so the
     accent keeps its weight where the size earns it. */
  --brick-display: #E07A5F;
  --stage-w: 54vw;
  --band-top: 0px;         /* where the sticky pills come to rest */
  --snap-top: 96px;        /* that, plus their height: rewritten by app.js */
  --sans: 'Archivo', system-ui, -apple-system, sans-serif;
  --mono: 'Spline Sans Mono', ui-monospace, monospace;
}

* { box-sizing: border-box; }

/* `hidden` is an attribute, and any display rule beats it. Every element here
   that carries `hidden` also carries a display, so this has to be explicit. */
[hidden] { display: none !important; }

html, body { height: 100%; }

/* SNAP SCROLLING (Jamie, 25 Aug 2026): the page moves stop to stop rather than
   drifting between them, because the camera is following the reading and a
   camera halfway between two stops is looking at nothing in particular.
   `mandatory` on `start` alignment is the safe pairing: a stop taller than the
   viewport can still be scrolled through, which `center` alignment cannot. */
/* Snapping is for sections made of STEPS. A section with one long stop is a
   document, and mandatory snapping with scroll-snap-stop: always makes the part
   of it below the fold unreachable: one nudge jumps to the next snap point
   instead of scrolling on, which reads as the page flicking to a card that is
   not there (Jamie, 25 Aug 2026). app.js sets no-snap for a one-stop section. */
html.no-snap { scroll-snap-type: none; }

html {
  scroll-snap-type: y mandatory;
  /* No scroll-behavior: smooth. It governs PROGRAMMATIC scrolls only, and a
     smooth one fights scroll-snap-stop: always, which is doing its job by
     halting the jump at the first snap point it passes. */
}
.topbar, .standfirst, .stop, .cta, .foot {
  scroll-snap-align: start;
  /* `always` is what makes it a step rather than a slide: a fast flick cannot
     sail past three stops and leave the model somewhere the reader never was. */
  scroll-snap-stop: always;
  scroll-margin-top: var(--snap-top);
}
/* The header snaps to the very top, or the pills become unreachable: with
   mandatory snapping there has to be a snap point at y=0 to scroll back to. */
/* On the narrow layout the header does not START at y=0, so its margin has to
   be the height of the stage band above it or it snaps the page down on load. */
.topbar { scroll-margin-top: var(--band-top); }

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--cream); color: var(--forest); padding: 12px 18px;
}
.skip:focus { left: 12px; top: 12px; }

/* ---------------------------------------------------------------- stage --- */

.stage {
  position: fixed; inset: 0 auto 0 0;
  width: var(--stage-w);
  background: var(--ink);
  overflow: hidden;
}

#site-model { display: block; width: 100%; height: 100%; }

.stage-status {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  margin: 0; font-family: var(--mono); font-size: 12px; letter-spacing: 0.14em;
  text-transform: uppercase; color: #5E6F64;
}
.stage-status[hidden] { display: none; }

.stage-top {
  position: absolute; left: 30px; top: 26px; right: 30px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  z-index: 3;                       /* above the gallery layer, which is its host */
}

.stage-tag {
  padding: 9px 16px; border: 1px solid rgba(15, 52, 46, 0.16);
  border-radius: 999px; background: rgba(15, 52, 46, 0.9);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--cream);
}

.stage-btn {
  cursor: pointer;
  padding: 9px 16px; border-radius: 999px;
  border: 1px solid rgba(15, 52, 46, 0.28);
  background: rgba(251, 246, 235, 0.86);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase; color: #294A40;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.stage-btn:hover { background: var(--cream); border-color: var(--forest); color: var(--forest); }
.stage-btn[aria-pressed="true"] {
  background: var(--brick-solid); border-color: var(--brick-solid); color: var(--cream);
}

.stage-foot {
  position: absolute; left: 30px; right: 30px; bottom: 26px; z-index: 3;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  /* Transparent bar spanning the stage: without this it takes every click in
     the bottom strip, which is where Back to the model lives. */
  pointer-events: none;
}
.stage-foot > * { pointer-events: auto; }

/* contact panel ------------------------------------------------------------- */
/* Same overlay pattern as the roam instructions: it sits on the stage, over the
   model, so it is reachable from every section rather than living inside one. */

.contact-panel {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 6; width: min(500px, calc(100% - 44px));
  max-height: calc(100% - 60px); overflow-y: auto;
  padding: 26px 28px 24px; border-radius: 14px;
  background: var(--forest); border: 1px solid var(--border);
  box-shadow: 0 26px 64px rgba(8, 26, 21, 0.45);
  color: var(--body);
}
.panel-kicker {
  margin: 0 0 6px; font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--brick-lift);
}
.contact-panel h2 {
  margin: 0 0 10px; font-size: 22px; font-weight: 600; color: var(--cream);
}
.contact-panel > p { margin: 0 0 14px; font-size: 15.5px; line-height: 1.55; }
.contact-panel .support-form { margin-top: 4px; }

.panel-close {
  position: absolute; right: 14px; top: 14px;
  width: 34px; height: 34px; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  border-radius: 999px; border: 1px solid var(--border);
  background: transparent; color: var(--muted);
}
.panel-close svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.panel-close:hover { color: var(--cream); border-color: var(--sage); }

/* free roam ---------------------------------------------------------------- */

.roam-help {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  z-index: 4; width: min(420px, calc(100% - 48px));
  padding: 24px 26px; border-radius: 14px;
  background: var(--forest); border: 1px solid var(--border);
  box-shadow: 0 24px 60px rgba(10, 30, 24, 0.35);
  color: var(--body);
}
.roam-help-title {
  margin: 0 0 12px; font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--brick-lift);
}
.roam-help ul { margin: 0 0 18px; padding-left: 20px; list-style: none; }
.roam-help li { position: relative; margin-bottom: 10px; font-size: 15.5px; line-height: 1.5; }
.roam-help li::before {
  content: ""; position: absolute; left: -20px; top: 0.62em;
  width: 7px; height: 2px; background: var(--brick); border-radius: 1px;
}
.roam-help b { color: var(--cream); font-weight: 600; }
.roam-help .btn { margin-right: 8px; }

/* Only while roaming, or a drag on the model would fight the page scroll. */
.stage.is-roaming #site-model { cursor: grab; touch-action: none; }
.stage.is-roaming #site-model:active { cursor: grabbing; }
.stage.is-roaming .markers { pointer-events: none; opacity: 0.35; }

/* The hint sits over the lawn, which is mid-green, so it needs its own ground
   rather than a colour chosen against the cream void behind the plinth. */
.stage-hint {
  display: inline-block;
  padding: 8px 14px; border-radius: 999px;
  background: rgba(251, 246, 235, 0.9);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: #3D4F45;
}

/* gallery ------------------------------------------------------------------ */
/* The art layer COVERS the canvas rather than replacing it, so the model keeps
   its box and its aspect and needs no resize on the way back. */

/* A COLUMN, not a centred grid: the arrows are flex siblings of the picture, so
   they can never end up drawn over it whatever shape the picture is. */
.artstage {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 12px;
  /* The hint belongs to the model and sat ON the picture here, so it is hidden
     in the gallery. The bottom room is for the contact button, which is not. */
  padding: 78px 30px 72px;
  background: var(--ink);
  z-index: 2;
}
.artstage img {
  max-width: 100%; min-height: 0;
  width: auto; height: auto;
  border-radius: 4px;
  box-shadow: 0 18px 48px rgba(20, 34, 28, 0.22);
  opacity: 0;
  transition: opacity 0.35s ease;
}
.artstage img.is-in { opacity: 1; }

/* Scrolling the reading column moves the gallery, which nobody knows until they
   try it. The arrows say so without a line of instructions. */
.art-arrow {
  flex: none; cursor: pointer;
  width: 40px; height: 40px; padding: 0;
  display: grid; place-items: center;
  border-radius: 999px;
  border: 1px solid rgba(15, 52, 46, 0.22);
  background: rgba(251, 246, 235, 0.92);
  color: #29493F;
  transition: background 0.18s ease, color 0.18s ease, opacity 0.18s ease;
}
.art-arrow svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.art-arrow:hover { background: var(--forest); color: var(--cream); border-color: var(--forest); }
/* Kept in the layout at the ends of the gallery rather than removed, or the
   picture jumps 52px up and down as the reader reaches the first and last. */
.art-arrow[disabled] { opacity: 0.22; pointer-events: none; }

.art-close {
  position: absolute; right: 30px; bottom: 26px;
  cursor: pointer; padding: 8px 15px; border-radius: 999px;
  border: 1px solid rgba(15, 52, 46, 0.25);
  background: rgba(251, 246, 235, 0.92);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: #29493F;
}
.art-close:hover { background: var(--forest); color: var(--cream); border-color: var(--forest); }

/* the strip inside a Possibilities stop ----------------------------------- */

.artstrip { margin: 18px 0 4px; }
.artstrip-lead {
  margin: 0 0 10px !important;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted); line-height: 1.5;
}
.artthumb {
  cursor: pointer; padding: 0; margin: 0 8px 8px 0;
  width: 128px; vertical-align: top;
  appearance: none; background: transparent; border: 0;
  display: inline-block; text-align: left;
}
.artthumb img {
  display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: 5px; border: 1px solid var(--border);
  transition: border-color 0.18s ease, opacity 0.18s ease;
  opacity: 0.82;
}
.artthumb span {
  display: block; margin-top: 5px;
  font-size: 12px; line-height: 1.35; color: var(--muted);
}
.artthumb:hover img { opacity: 1; border-color: var(--sage); }
.artthumb[aria-current="true"] img { opacity: 1; border-color: var(--brick); }
.artthumb[aria-current="true"] span { color: var(--cream); }

/* markers ------------------------------------------------------------------ */

/* Only the HINT goes in the gallery, not the whole foot: the contact button
   lives there now and it belongs on every section. */
.stage.is-gallery .stage-hint { display: none; }

/* The CONTAINER must not take clicks. It covers the whole canvas, so with the
   default pointer-events it swallowed every click on the model, including the
   double-click that is meant to fly there. Only a shown marker is clickable. */
.markers { position: absolute; inset: 0; pointer-events: none; }

.marker {
  position: absolute;
  width: 30px; height: 30px;
  margin: -15px 0 0 -15px;          /* the anchor is the centre, not the corner */
  display: grid; place-items: center;
  border-radius: 999px;
  border: 1.5px solid rgba(15, 52, 46, 0.22);
  background: rgba(15, 52, 46, 0.92);
  color: var(--cream);
  font-family: var(--mono); font-size: 12px;
  transition: opacity 0.35s ease, transform 0.35s ease, background 0.2s ease;
  opacity: 0;
  pointer-events: none;
}
.marker.is-shown { opacity: 1; pointer-events: auto; }
.marker.is-live {
  background: var(--brick-solid); border-color: var(--brick-solid);
  transform: scale(1.16);
  /* The live marker is never allowed to end up underneath a neighbour: at a
     wide camera the Mansion and the Winter Garden project within a few pixels
     of each other, and the one being talked about has to be the one on top. */
  z-index: 2;
}

/* ---------------------------------------------------------------- reading - */

.reading {
  margin-left: var(--stage-w);
  min-height: 100%;
  background: var(--forest);
  padding: 0 clamp(28px, 3.4vw, 52px) 0;
  display: flex; flex-direction: column;
}

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding: 26px 0 0;
}

.wordmark { text-decoration: none; display: block; }
.wordmark-kicker {
  display: block; font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--brick-lift);
}
.wordmark-name {
  display: block; font-size: 17px; font-weight: 600; color: var(--cream);
}

.menu-btn, .menu button {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted);
}
.menu-btn:hover, .menu button:hover { color: var(--cream); }

/* Horizontal, wrapping. A stacked list of five pushed the pills a screen down
   whenever the menu was open. */
.menu {
  display: flex; flex-direction: row; flex-wrap: wrap; align-items: center;
  gap: 8px 10px; padding: 16px 0 14px; border-bottom: 1px solid var(--border);
}
.menu a, .menu button {
  color: var(--body); text-decoration: none; font-size: 14px;
  padding: 10px 15px; min-height: 44px; display: inline-flex; align-items: center;
  border: 1px solid var(--border); border-radius: 999px; background: none;
  font-family: var(--sans); letter-spacing: 0; text-transform: none;
}
.menu a:hover, .menu button:hover {
  color: var(--cream); border-color: var(--brick); background: var(--forest-lift);
}
@media (max-width: 620px) { .menu a, .menu button { font-size: 13px; padding: 9px 13px; } }

/* pills -------------------------------------------------------------------- */

/* Four pills, two by two. Four across a reading column leaves each one narrower
   than its own label, and "Imagining the potential" is the label that proves it.
   Sticky, because snap scrolling means a reader can be six stops down with no
   cheap way back to the top: the section switch has to travel with them. */
.pills {
  position: sticky; top: 0; z-index: 5;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  padding: 14px 0 10px;
  background: var(--forest);
  box-shadow: 0 10px 18px -12px rgba(6, 24, 20, 0.9);
}

.pill {
  appearance: none; cursor: pointer; text-align: left;
  padding: 8px 12px; border-radius: 8px;
  border: 1px solid var(--border); background: transparent;
  color: var(--body); font-family: inherit;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.pill:hover { border-color: var(--sage); }
.pill-name {
  display: block; font-family: var(--mono); font-size: 11.5px;
  letter-spacing: 0.08em; text-transform: uppercase; line-height: 1.25;
}
.pill-note {
  /* Sits on a lifted pill, where --muted cannot reach AAA. */
  display: block; margin-top: 1px; font-size: 12px; color: var(--sage);
}
.pill[aria-pressed="true"] {
  background: var(--cream); border-color: var(--cream); color: var(--forest);
}
/* On the cream pill the ground is light, so the note darkens instead. 7.4:1. */
.pill[aria-pressed="true"] .pill-note { color: #46564D; }

/* The seventh pill. Six are the argument in order and history is the background
   to it, so it takes the last row whole: an orphan in a three-column grid reads
   as a mistake, a full-width row reads as a second register. */
.pill-wide { grid-column: 1 / -1; }

/* stops -------------------------------------------------------------------- */

/* Switching section scrolls here, and the pills are sticky over it, so it needs
   the same offset every snap point has or the standfirst lands underneath them. */
.stops { flex: 1 0 auto; padding-bottom: 40px; scroll-margin-top: var(--snap-top); }

.standfirst {
  margin: 26px 0 8px;
  font-size: 18px; line-height: 1.55; color: var(--sage);
  border-left: 2px solid var(--brick); padding-left: 18px;
}

.stop {
  padding: 34px 0;
  border-top: 1px solid var(--border);
  /* scroll-margin-top is set by the snap block above. It used to be repeated
     here at 20px, and because this rule comes later it WON: every stop snapped
     to 20px and landed underneath the sticky pills. */
}
.stop:first-of-type { border-top: 0; }

.eyebrow {
  margin: 0 0 12px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--brick-lift);
}
.eyebrow span { color: var(--body); margin-left: 10px; }

/* When a building's date is known it goes under the title rather than into the
   eyebrow, which already carries where you are standing (Jamie, 27 Aug 2026).
   Qualified by .stop because .section-letter p is (0,1,1) and would otherwise
   win on font-size — the same collision the history timeline hit. */
.stop .dateline {
  margin: -8px 0 16px; font-family: var(--mono); font-size: 12px;
  line-height: 1.4; letter-spacing: .1em; color: var(--sage);
}

.stop h2 {
  margin: 0 0 16px;
  font-size: clamp(26px, 2.5vw, 36px); line-height: 1.14;
  font-weight: 600; color: var(--cream); letter-spacing: -0.01em;
}

/* The stop the reader is parked on, matched to its live marker on the model.
   --brick-display, NOT --brick-lift or --brick-solid: this h2 is clamp(26px..)
   display type, which is the one size band where the brand terracotta clears
   AAA at 4.5:1 (see the palette note at the top). --brick-solid is a fill and
   measures 2.4:1 as text on --forest. */
.stop h2 { transition: color 220ms ease; }
.stop.is-current h2 { color: var(--brick-display); }

.stop p { margin: 0 0 14px; }

/* Reading-column links. They were falling through to the browser default, which
   is blue with an underline on a dark green ground. The STANDFIRST joined this
   list on 27 Aug 2026: no standfirst had ever carried a link until the history
   section credited the Friends in its opening sentence, and it came out blue.
   Any new text block that can hold a link belongs here. */
.stop a:not(.btn), .standfirst a, .foot a, .aside a {
  color: var(--brick-lift);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(224, 122, 95, 0.5);
}
.stop a:not(.btn):hover, .standfirst a:hover, .foot a:hover, .aside a:hover {
  color: var(--cream); text-decoration-color: var(--cream);
}

.aside {
  border-left: 2px solid var(--border);
  padding-left: 18px; color: var(--muted); font-size: 16px;
}

.options { margin: 4px 0 14px; padding-left: 22px; }
.options li { margin-bottom: 10px; }
.options b, .points b { color: var(--cream); font-weight: 600; }

/* The unordered sibling of .options. Marker in brick so a list of specifics
   reads as a list at a glance, without the numbering that .options uses to say
   "five options, no preference between them". */
.points { margin: 4px 0 16px; padding-left: 20px; list-style: none; }
.points li { position: relative; margin-bottom: 11px; }
.points li::before {
  content: ""; position: absolute; left: -20px; top: 0.62em;
  width: 7px; height: 2px; background: var(--brick); border-radius: 1px;
}

/* the introduction ---------------------------------------------------------- */
/* One stop, no numbers, and set larger than the sections it introduces. The
   other three are arguments made in stages; this one is a letter. */

/* Full column width, like every other section (Jamie, 25 Aug 2026). The measure
   was narrower here because a letter reads better short, and it made the
   introduction look like a different page rather than the first one. */
.section-letter .stop { border-top: 0; padding-top: 26px; }
.section-letter p { margin: 0 0 15px; font-size: 17px; line-height: 1.58; }
.section-letter b { color: var(--cream); font-weight: 600; }

.letter-open {
  font-size: clamp(20px, 1.65vw, 23px) !important;
  /* 1.5 is the AAA floor for line spacing (1.4.8), and this is the largest
     block of text on the page. */
  line-height: 1.5 !important;
  color: var(--cream);
  margin-bottom: 22px !important;
  letter-spacing: -0.005em;
}

/* An open letter signed by a person, so there is a person on it — beside the
   signature rather than floated in the text, which is where a letterhead goes
   and where the eye is already looking when it reaches the name. */
/* A square, floated, with the letter running round it. Square rather than the
   picture's own 4:3 so the wrap stays a clean column rather than stepping. */
.letter-figure {
  float: right; width: 232px; margin: 4px 0 16px 24px;
}
.letter-figure img {
  display: block; width: 232px; height: 232px;
  object-fit: cover; border-radius: 10px; border: 1px solid var(--border);
}
.letter-figure figcaption {
  margin-top: 7px; font-size: 12.5px; line-height: 1.4; color: var(--muted);
}

.letter-sign-row {
  display: flex; align-items: center; gap: 18px;
  margin-top: 26px; padding-top: 22px;
  border-top: 1px solid var(--border);
}
.letter-portrait { margin: 0; width: 104px; flex: none; }
.letter-portrait img {
  display: block; width: 104px; height: 104px;
  object-fit: cover; object-position: 50% 22%;   /* the face, not the middle */
  border-radius: 999px; border: 1px solid var(--border);
}

.letter-sign {
  margin: 0 !important;
  font-weight: 600; color: var(--cream);
}
/* Jamie's name links to his profile wherever it appears (26 Aug 2026). In the
   signature it keeps the signature's own colour and weight: a brick-coloured
   link there reads as a stray call to action rather than as a name signed at
   the bottom of a letter. The underline still marks it as a link, so it is not
   distinguished by colour alone. Placed after `.stop a:not(.btn)` because it
   ties that rule on specificity and has to win on order. */
.stop .letter-sign a {
  color: inherit;
  text-decoration-color: rgba(240, 230, 210, 0.4);
  text-underline-offset: 4px;
}
.stop .letter-sign a:hover { text-decoration-color: currentColor; }

.letter-sign span {
  display: block; margin-top: 2px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--muted); font-weight: 400;
}

.letter-next { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; clear: both; }

/* support ------------------------------------------------------------------- */

.pledge {
  margin: 22px 0; padding: 20px 22px;
  border-left: 3px solid var(--brick);
  background: var(--forest-lift);
  border-radius: 0 10px 10px 0;
}
.pledge p { margin: 0 !important; font-size: 18px !important; color: var(--cream); line-height: 1.5 !important; }

/* Two columns: name over the choices on the left, postcode over the comment on
   the right, so the long free-text field sits beside the short ones instead of
   under them (Jamie, 25 Aug 2026). */
.support-form {
  margin: 26px 0 8px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 0 22px;
  align-items: start;
}
.f-name      { grid-column: 1; grid-row: 1; }
.f-email     { grid-column: 2; grid-row: 1; }
.f-postcode  { grid-column: 1; grid-row: 2; }
.f-visibility{ grid-column: 1; grid-row: 3; }
.f-mailing   { grid-column: 1; grid-row: 4; }
.f-comment   { grid-column: 2; grid-row: 2 / span 3; }
.f-wide      { grid-column: 1 / -1; }
.f-submit    { grid-column: 1 / -1; margin-top: 4px; }
.support-form .field { margin-bottom: 16px; border: 0; padding: 0; min-width: 0; }
.support-form .f-comment textarea { min-height: 148px; }
.support-form label, .support-form legend {
  display: block; margin-bottom: 6px; padding: 0;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--sage);
}
.support-form label span { color: var(--muted); }
.support-form input[type="text"], .support-form input[type="email"],
.support-form input:not([type]), .support-form textarea {
  width: 100%; padding: 11px 13px;
  border: 1px solid var(--border); border-radius: 8px;
  background: rgba(6, 26, 22, 0.45); color: var(--cream);
  font-family: inherit; font-size: 16px;   /* 16px or iOS zooms the page on focus */
}
.support-form textarea { resize: vertical; line-height: 1.5; }
.support-form input:focus, .support-form textarea:focus { border-color: var(--sage); outline: none; }
.field-help { display: block; margin-top: 5px; font-size: 13px; color: var(--muted); line-height: 1.45; }

/* `.support-form .choice` rather than `.choice`: `.support-form label` is one
   class plus one element and outranks a bare class, so the radio labels were
   inheriting the uppercase mono field-label style. */
.support-form .choice {
  display: flex; align-items: flex-start; gap: 9px;
  margin-bottom: 8px;
  text-transform: none; letter-spacing: 0;
  font-family: var(--sans); font-size: 15.5px; color: var(--body);
  line-height: 1.45; font-weight: 400;
}
.support-form .choice input { margin-top: 3px; accent-color: var(--brick); flex: none; }
.support-form .choice-block { margin: 6px 0 18px; }

/* The honeypot is hidden from people and left reachable to anything filling
   fields by name. off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Used by several labels in the markup and never defined, so "Seek through the
   episode" and its siblings were rendering as visible text. Present for screen
   readers, clipped to nothing on screen. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* listen ------------------------------------------------------------------- */
/* Same overlay pattern as the roam help and the contact panel: it sits ON the
   stage, so it is reachable from any stop in the section without the reading
   column having to make room for it. */

.listen-panel {
  position: absolute; left: 30px; top: 92px; z-index: 6;
  width: min(360px, calc(100% - 60px));
  padding: 20px 22px 18px;
  border-radius: 12px; border: 1px solid var(--brick);
  background: var(--forest-lift);
  box-shadow: 0 18px 40px -18px rgba(6, 26, 22, 0.8);
}
.listen-panel h3 { margin: 0 0 14px; font-size: 19px; font-weight: 600; color: var(--cream); }

.listen-transport { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.listen-play {
  flex: none; min-width: 74px; min-height: 44px; padding: 0 14px; cursor: pointer;
  border-radius: 999px; border: 1px solid var(--brick-solid);
  background: var(--brick-solid); color: var(--cream);
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
}
.listen-seek { flex: 1 1 auto; min-width: 0; display: block; }
.listen-seek input { width: 100%; accent-color: var(--brick-lift); }
.listen-time { flex: none; font-family: var(--mono); font-size: 12px; color: var(--sage); }
.listen-time b { color: var(--cream); font-weight: 500; }

.listen-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.listen-list button {
  width: 100%; min-height: 44px; padding: 9px 12px; cursor: pointer; text-align: left;
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  border-radius: 8px; border: 1px solid var(--border); background: none; color: var(--body);
  font-family: var(--sans); font-size: 14px;
}
.listen-list button b { font-weight: 500; }
.listen-list button span { font-family: var(--mono); font-size: 11.5px; color: var(--sage); }
.listen-list button:hover { border-color: var(--brick); color: var(--cream); }
.listen-list button[aria-current="true"] { border-color: var(--brick); background: var(--forest); color: var(--cream); }

@media (max-width: 900px) {
  /* The stage is a 42vh band on a phone, so the panel spans it instead of
     floating in a corner of it. */
  .listen-panel { left: 12px; right: 12px; top: 12px; width: auto; padding: 16px 16px 14px; }
  .listen-panel h3 { font-size: 17px; margin-bottom: 10px; }
  .listen-list { margin-bottom: 10px; }
}

/* the satellite view ------------------------------------------------------- */

.mapstage {
  position: absolute; inset: 0; z-index: 3;
  background: var(--forest-deep, #0A1E24);
}
.map-frame { position: absolute; inset: 0; }
.map-frame iframe { display: block; width: 100%; height: 100%; border: 0; }

/* the paper reader --------------------------------------------------------- */

.paperstage {
  position: absolute; inset: 0; z-index: 3;
  display: flex; flex-direction: column;
  background: var(--paper-dark, #10221F);
}
.paper-scroll {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 60px 22px 58px; scroll-behavior: smooth;
}
.paper-scroll:focus-visible { outline: 2px solid var(--brick-lift); outline-offset: -4px; }
.paper-scroll img {
  display: block; width: 100%; max-width: 780px; margin: 0 auto 16px;
  border-radius: 3px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
  background: #FFF; aspect-ratio: 909 / 1287;
}
/* Top right: the bottom left of the stage already carries the contact chip,
   and the two overlapped. */
.paper-get {
  position: absolute; right: 14px; top: 14px; z-index: 4;
  padding: 8px 15px; border-radius: 999px;
  background: rgba(10, 30, 36, 0.9); border: 1px solid var(--border);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--sage); text-decoration: none;
}
.paper-get:hover { color: var(--cream); border-color: var(--brick); }

.paper-status {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  margin: 0; padding: 7px 15px; border-radius: 999px;
  background: rgba(10, 30, 36, 0.9); border: 1px solid var(--border);
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--sage); pointer-events: none;
}

@media (max-width: 900px) {
  .paper-scroll { padding: 54px 12px 52px; }
}

/* share -------------------------------------------------------------------- */

.share-panel {
  margin: 22px 0 4px; padding: 20px 22px;
  border-radius: 12px; border: 1px solid var(--brick);
  background: var(--forest-lift);
}
.share-panel h3 { margin: 0 0 8px; font-size: 20px; font-weight: 600; color: var(--cream); }
.share-panel > p { margin: 0 0 14px; font-size: 15.5px; line-height: 1.55; }
.share-row { display: flex; flex-wrap: wrap; gap: 9px; }
.share-row .btn { padding: 10px 18px; font-size: 14.5px; }

/* the signature wall ------------------------------------------------------- */

.signatures {
  margin: 30px 0 6px; padding-top: 22px;
  border-top: 1px solid var(--border);
}
.sig-count { margin: 0 0 14px; font-size: 16px; color: var(--body); }
.sig-count b { color: var(--brick-lift); font-size: 30px; font-weight: 600; }
.sig-count.is-empty { color: var(--muted); font-style: italic; }

.sig-list { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 7px; }
.sig-list li {
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: rgba(6, 26, 22, 0.35);
  font-size: 14px; color: var(--body);
}
.sig-list li span {
  margin-left: 7px; font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.08em; color: var(--sage);
}
.sig-list li.is-anon { color: var(--muted); font-style: italic; }
.sig-note { margin: 12px 0 0; font-size: 13.5px; color: var(--muted); }

.form-status { margin: 12px 0 0; font-size: 15px; color: var(--muted); min-height: 1.4em; }
.form-status.is-bad { color: #F0A28C; }
.form-status.is-good { color: var(--sage); }

.contact-box { margin-top: 30px; }
.contact-box h3 { margin-bottom: 8px; }
.contact-form-v2 { margin-top: 18px; }
.contact-form-v2 .f-comment { grid-column: 1 / -1; grid-row: auto; }

@media (max-width: 760px) {
  .support-form { grid-template-columns: 1fr; }
  .support-form > * { grid-column: 1 !important; grid-row: auto !important; }
}

/* timeline ----------------------------------------------------------------- */
/* The history page. One rule down the left with a marker per entry, because
   the thing a reader wants here is the ORDER: this estate's problem is that
   four owners inherited it in sequence and none of them inherited the whole. */

.era { margin: 40px 0 6px; }
.era:first-of-type { margin-top: 26px; }
.era .era-span {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.4;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--brick-lift); margin: 0 0 6px;
}
.era h2 { margin: 0 0 4px; }

.timeline { list-style: none; margin: 18px 0 0; padding: 0 0 0 26px; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 4px; top: 6px; bottom: 6px;
  width: 1px; background: var(--border);
}
.timeline > li { position: relative; padding: 0 0 26px; }
.timeline > li::before {
  content: ""; position: absolute; left: -26px; top: 7px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--forest); border: 1px solid var(--brick);
}
/* An entry that rests on the Friends' record rather than on a public document
   is marked, so the page never quietly levels the two. */
.timeline > li.is-friends::before { background: var(--brick); }
.timeline .tl-when {
  margin: 0 0 3px; font-family: var(--mono); font-size: 12px; line-height: 1.4;
  letter-spacing: .1em; color: var(--sage);
}
.timeline h3 {
  margin: 0 0 7px; font-size: 18.5px; font-weight: 600; color: var(--cream);
  letter-spacing: -.01em; text-wrap: balance;
}
.timeline p { margin: 0 0 10px; }
.timeline p:last-child { margin-bottom: 0; }
.timeline .tl-src {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
  letter-spacing: .04em; color: var(--muted); max-width: 62ch;
}

/* cta ---------------------------------------------------------------------- */

.cta {
  margin-top: 10px; padding: 30px;
  background: var(--forest-lift); border: 1px solid var(--border);
  border-radius: 14px;
}
.cta h3 {
  margin: 0 0 12px; font-size: 23px; font-weight: 600; color: var(--cream);
}
/* A sub-heading inside a picture card, for the one card that carries an argument
   as well as a caption. */
.stop .card-head {
  margin: 26px 0 10px; padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 17px; font-weight: 600; color: var(--cream);
}
.stop .cta-row { margin-top: 24px; }

.cta h4 {
  margin: 26px 0 10px; padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 17px; font-weight: 600; color: var(--cream);
}
.cta p { margin: 0 0 18px; }

.terms { margin: 0 0 20px; }
.terms > div { padding: 12px 0; border-top: 1px solid var(--border); }
.terms dt {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--sage); margin-bottom: 5px;
}
.terms dd { margin: 0; font-size: 15.5px; }

.cta-row { display: flex; flex-wrap: wrap; gap: 10px; }

/* The same button at the top of a paper's section as at the bottom of it, so
   somebody who has decided in the first paragraph does not have to scroll the
   whole argument to find the door (Jamie, 27 Aug 2026). It sits under the
   standfirst, which carries its own left rule, so it is indented to that rule
   rather than hanging off it. */
.cta-row-top { margin: 18px 0 4px; padding-left: 20px; }
@media (max-width: 760px) { .cta-row-top { padding-left: 0; } }

/* The secondary button sits beside a solid brick one, and in pale green it read
   as disabled rather than as the other half of a pair (Jamie, 25 Aug 2026). */
.btn {
  display: inline-block; text-decoration: none;
  /* .btn is worn by <a> in the CTAs and by <button> in the introduction, and a
     <button> carries a user-agent buttonface background that an <a> does not.
     Without this reset the secondary button paints light grey, which put the
     new text colour on the wrong ground entirely. */
  appearance: none; background: transparent;
  /* .btn is worn by <a> and by <button>, and only the <a> gets a pointer and
     the page font for free. Set on the base rule rather than per call site:
     it was on .letter-next .btn only, so the Give your support button in a CTA
     showed a text caret while the link beside it showed a hand. */
  cursor: pointer; font-family: inherit;
  padding: 13px 22px; border-radius: 999px;
  border: 1px solid rgba(194, 90, 66, 0.5);
  color: var(--brick-lift);
  font-size: 15.5px; font-weight: 600;
  transition: border-color 0.18s ease, color 0.18s ease;
}
/* Hover brightens rather than filling: cream on a brick fill is 4.03:1, which
   is the same failure one step along. */
.btn:hover { border-color: var(--brick-lift); color: var(--cream); }
.btn-solid {
  background: var(--brick-solid); border-color: var(--brick-solid); color: var(--cream);
}
.btn-solid:hover { background: #9C4733; border-color: #9C4733; }

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

.stopnav {
  position: sticky; bottom: 0;
  display: flex; gap: 6px; flex-wrap: wrap;
  padding: 12px 0; margin-top: auto;
  background: linear-gradient(to top, var(--forest) 72%, rgba(15, 52, 46, 0));
}
.stopnav button {
  cursor: pointer; width: 30px; height: 30px;
  border-radius: 999px; border: 1px solid var(--border);
  background: transparent; color: var(--muted);
  font-family: var(--mono); font-size: 11.5px;
}
.stopnav button:hover { border-color: var(--sage); color: var(--cream); }

.stopnav button[aria-current="true"] {
  background: var(--brick-solid); border-color: var(--brick-solid); color: var(--cream);
}

.foot {
  padding: 22px 0 34px; border-top: 1px solid var(--border);
  font-size: 13.5px; color: var(--muted);
}

/* The trailing spacer is GONE (Jamie, 25 Aug 2026: nothing needs to scroll past
   the footer). It existed so the last snap point could reach the snap line in a
   snapping section, and it cost a screen of empty green under the footer on
   every section. The sections that still snap are the ones whose stops all fit,
   so their last stop reaches the line without it. */
.foot p { margin: 0 0 10px; }

/* day / night ------------------------------------------------------------- */
/* Bottom right, above the accessibility button, which is where both live on the
   root page and on distributedrepublic.xyz. */

#nightToggle {
  position: fixed; right: 20px; z-index: 99999;
  /* Sits directly above the accessibility FAB stack. Derived from the
     stack's MEASURED height (published by analytics-optout.js) rather
     than a constant: the stack is bottom-anchored, so every button
     added to it grows it upwards into this one. 88px was correct for a
     one-button stack and silently wrong the moment there were two. */
  bottom: calc(24px + var(--axs-stack-h, 52px) + 12px);
  width: 52px; height: 52px; border-radius: 16px;
  /* The page's orange in both states, and !important because the widget's dark
     mode paints every element #1A1A1A. */
  background-color: var(--brick) !important; color: var(--cream) !important;
  border: 1px solid var(--brick); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 22px -8px rgba(6, 30, 24, 0.7);
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}
#nightToggle:hover { transform: scale(1.07); }
#nightToggle svg { width: 22px; height: 22px; }
html.axs-dark-mode #nightToggle { border-color: var(--brick-lift); }

/* The widget's dark mode forces #1A1A1A on every element with !important, so
   these have to shout back. Without them the stage takes the widget's grey, the
   model sits on a ground lighter than itself, and the whole left half reads as
   an empty black panel. */
html.axs-dark-mode .stage,
html.axs-dark-mode .artstage { background-color: #0A1E24 !important; }
html.axs-dark-mode .stage-tag,
html.axs-dark-mode .stage-btn,
html.axs-dark-mode .stage-hint,
html.axs-dark-mode .art-close,
html.axs-dark-mode .art-arrow {
  background-color: rgba(10, 30, 36, 0.9) !important;
  color: var(--cream) !important; border-color: var(--border) !important;
}
html.axs-dark-mode .marker { border-color: rgba(200, 226, 214, 0.25) !important; }
html.axs-dark-mode .contact-panel,
html.axs-dark-mode .roam-help { background-color: #0E2A24 !important; }

@media (max-width: 768px) {
  /* Night in the corner, accessibility horizontally to its left (Jamie, 25 Aug
     2026). Both were stacked bottom right, over the reading column. The widget's
     own stack is `position: fixed` inside `#axs-widget-root`, so it is overridden
     here at matching specificity rather than by editing axs-widget.css, which is
     shared with distributedrepublic.xyz. Row, not column, so a second fab would
     grow along the top edge rather than down over the model. */
  #nightToggle {
    top: 12px; right: 12px; bottom: auto;
    width: 46px; height: 46px; border-radius: 14px;
  }
  #axs-widget-root .axs-fab-stack {
    top: 12px; right: 68px; bottom: auto;
    flex-direction: row; gap: 10px;
  }
  #axs-widget-root .axs-fab { width: 46px; height: 46px; }

}

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

/* documents ---------------------------------------------------------------- */
/* A page with no stage: the reading column is the whole page. */

body.doc { overflow-y: auto; }
body.doc .reading { margin-left: 0; max-width: 74ch; margin-inline: auto; }
body.doc .stops { padding-bottom: 10px; }
body.doc h2 {
  margin: 30px 0 12px; font-size: clamp(20px, 1.7vw, 24px);
  color: var(--cream); font-weight: 600;
}
body.doc .menu-btn { text-decoration: none; }

/* --------------------------------------------------------------- narrow --- */
/* Below 900px the split becomes a stacked one, model on TOP and the text
   scrolling beneath it (Jamie, 25 Aug 2026 — tried the other way round the same
   evening and preferred this). The model holds its own band at the top of the
   window and the reading column runs under it, which is the same relationship
   as the wide layout with the axis turned. */

@media (max-width: 900px) {
  :root { --stage-w: 100vw; --stage-h: 42vh; }

  .stage {
    inset: 0 0 auto 0; height: var(--stage-h);
    border-bottom: 1px solid var(--border);
  }
  /* Nothing sits ON the model on a phone (Jamie, 25 Aug 2026). The band is only
     354px tall, and a label plus three chips over it left very little estate to
     look at. The two LABELS go entirely, since the reading column already names
     the stop; the three CONTROLS are not lost, they live in the menu, which is
     why Satellite and Free roam were added to it. */
  .stage-top, .stage-foot { display: none; }

  /* The gallery FILLS the band on a phone (Jamie, 25 Aug 2026). At 354px tall,
     150px of vertical padding plus two 40px arrows in the column flow left the
     picture about a third of the space it had to work with. Padding goes, the
     image covers the band, and the arrows sit ON it. `cover` rather than
     `contain` because the ask is to fill the space: a letterboxed picture in a
     band this shallow is the problem, not the fix. The caption is still the
     reading column underneath, which is why the gallery does not go full
     screen here. */
  .artstage { padding: 0; gap: 0; }
  .artstage img {
    width: 100%; height: 100%; max-width: none;
    object-fit: cover; border-radius: 0;
  }
  /* Arrows on the SIDE edges, not top and bottom. Overlaid at top centre the
     previous-arrow ran 10px into "Back to the model", and the corners are where
     a full-bleed picture has to put its controls. Left and right is also what a
     phone reader expects of a gallery. The chevrons are drawn pointing up and
     down for the desktop column, so they turn a quarter to match. */
  .art-arrow {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
    background: rgba(251, 246, 235, 0.86);
  }
  .art-arrow[data-art-step="-1"] { left: 12px; }
  .art-arrow[data-art-step="1"]  { right: 12px; }
  .art-arrow svg { transform: rotate(-90deg); }
  /* Top LEFT: the night and accessibility buttons own the top right corner on a
     phone, and the arrows are on the side edges, so this is the free corner. */
  .art-close { position: absolute; top: 12px; left: 12px; right: auto; bottom: auto; z-index: 3; }

  .reading {
    margin-left: 0; margin-top: var(--stage-h);
    padding: 0 20px;
    border-top: 0;
  }

  /* A 35 page paper or a map in a 42vh strip is unreadable, so those take the
     whole screen. The ART gallery deliberately does NOT: its caption is the
     reading column, and going full screen there covers the text the picture
     illustrates and hides the stop nav with it. The model stays a band too. */
  .stage.is-fullstage { inset: 0; height: 100dvh; z-index: 20; }


  .letter-figure { float: none; width: 100%; margin: 14px 0 18px; }
  .letter-figure img { width: 100%; height: 200px; }

  .pills {
    grid-template-columns: 1fr 1fr;
    /* Under the fixed stage band, not under the top of the window. app.js reads
       this computed `top` to work out where a scrolled stop must land, so it has
       to be the real offset rather than 0. */
    top: var(--stage-h);
    padding: 12px 20px; margin: 0 -20px;
  }
  .pill { padding: 10px 12px; }
  .pill-name { font-size: 11px; }
  .pill-note { display: none; }

  .stage-top { left: 16px; right: 16px; top: 14px; }
  .artthumb { width: calc(50% - 6px); margin-right: 6px; }
  .art-close { top: 12px; left: 12px; right: auto; bottom: auto; }
  .contact-panel { padding: 20px 18px 18px; }
  .roam-help { padding: 18px 18px; }
  .roam-help li { font-size: 14.5px; }
  /* This used to be `padding: 96px 16px 60px`, to clear a tag and a gallery
     button that wrapped to two rows at this width. Neither is on the model any
     more, so the padding was reserving room for nothing and holding the picture
     to about half the band. */
  .artstage { padding: 0; gap: 0; }
  .art-arrow { width: 32px; height: 32px; }
  .art-arrow svg { width: 17px; height: 17px; }
  
  .stopnav { position: static; }
}

@media (prefers-reduced-motion: reduce) {
  .marker, .artstage img, .stop h2 { transition: none; }
  /* Snapping stays under reduced motion: it is a scroll position, not an
     animation. */
}


/* ---------------------------------------------------------------------------
   WCAG AAA pass, 25 Aug 2026.
   Everything here was measured rather than guessed: contrast against the real
   computed background, target sizes against real bounding boxes.
   --------------------------------------------------------------------------- */

/* 1.4.8 Visual Presentation: line spacing at least 1.5 within a paragraph, and
   paragraph spacing at least 1.5x that again. */
.reading p, .reading li, .stop p, .stop li { line-height: 1.62; }
.reading p + p, .stop p + p { margin-top: 1.05em; }

/* 1.4.8 again: no more than 80 characters a line. The ch unit is the width of
   a "0", which is close enough to the average glyph for this to be the real
   measure rather than a guess at a pixel width. */
.reading p, .reading li, .stop p, .stop li, .aside, .standfirst { max-width: 74ch; }

/* 2.5.5 Target Size (Enhanced): 44x44 CSS pixels. The markers are 30-35px
   circles ON the model and enlarging them would change the drawing, so the
   TARGET grows and the dot does not. */
.stage-btn, .menu-btn, .art-close, .paper-get, .btn {
  min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
}
/* NOT position:relative. The markers are absolutely positioned from the model's
   projection, and this rule sits later in the file than that one, so relative
   dropped all fourteen into normal document flow: each landed ~13px below the
   last (its own height minus its centring margin), which is why the drift grew
   marker by marker in DOM order and read as a small-screen fault. An absolutely
   positioned element is a containing block for ::before just the same. */
.marker { position: absolute; }
.marker::before {
  content: ''; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}

/* 1.4.11 Non-text Contrast: the focus ring has to clear 3:1 against both the
   thing it rings and the ground behind it. */
:focus-visible { outline: 3px solid var(--brick-display); outline-offset: 2px; }

/* 1.4.12 Text Spacing: the page must survive a reader overriding all four of
   these, so nothing that holds text may be a fixed height. */
.stop, .reading p, .btn, .stage-btn { height: auto; }


/* The last of the AAA measurements, taken from the rendered pages rather than
   assumed: the letter opener carried line-height 1.38, the footer ran to 88
   characters a line, and the menu button was 35px wide against the 44 that
   2.5.5 asks for. */
.foot p { max-width: 74ch; }
.menu-btn, .stage-btn, .art-close, .paper-get { min-width: 44px; }


/* Markers scale with the stage. They were a fixed 30px, so on a small screen
   the model shrank underneath them and the numbers bunched into each other:
   at 1366 the Mansion's four markers overlapped, at 1920 they did not. Nothing
   about their POSITIONS was wrong, which is why it read as a small-screen bug.
   The 44px target underneath is untouched, so they get smaller to look at and
   not to hit. */
@media (max-width: 1500px) {
  .marker { width: 26px; height: 26px; margin: -13px 0 0 -13px; font-size: 11px; }
}
@media (max-width: 900px) {
  .marker { width: 23px; height: 23px; margin: -11.5px 0 0 -11.5px; font-size: 10px; }
}
