/* ==========================================================================
   Wodonga Wire — publication shell

   The thin shared layer every page family loads FIRST. It owns exactly the
   parts of a page a reader uses to know they are still inside one
   publication: the tokens the outer frame needs (including the three type
   faces and the motion floor), the page ground, the container metric and its
   responsive gutters, the vertical page structure, the skip link, the
   masthead with its wordmark and primary navigation, the focus treatment of
   those shell controls, the identity band every page enters through
   (D-069), and the footer.

   Both base templates consume it — base.html (site.css families) and
   foundation_base.html (foundation families) — through the macros in
   app/templates/_publication.html. Everything inside <main> belongs to the
   family stylesheet that follows this one: editorial composition, register
   layouts, the map workspace, charts, tables, chapter navigation and every
   state presentation. See decisions/D-065.

   The values are the Site Foundation's (docs/design/WODONGA_WIRE_SITE_FOUNDATION.md,
   D-026), which is the canonical outer design system; foundation.css no longer
   redefines the tokens carried here. Three breakpoints only — 640, 900, 1100.
   ========================================================================== */

:root {
  /* ground and ink */
  --bg: #f5f4ed;
  --surface: #faf9f5;
  --surface-warm: #e8e6dc;
  --fg: #141413;
  --fg-2: #3d3d3a;
  --muted: #5e5d59;
  --meta: #6b6a63; /* 12px text: 4.9:1 on --bg, 5.2:1 on --surface */
  --border: #f0eee6;
  --border-soft: #e8e6dc;

  /* the one accent */
  --accent: #c96442;
  --accent-on: #faf9f5;
  --accent-hover: color-mix(in oklab, var(--accent), black 8%);
  --accent-active: color-mix(in oklab, var(--accent), black 14%);

  /* type — the publication's three faces, declared once. Every family
     aliases its own type tokens to these (site.css --serif/--sans/--mono,
     case-study.css --cs-font-*), so the rendered face never changes between
     families. No face is self-hosted: the stacks name what a reader's
     platform delivers, and they are ordered deliberately — Georgia first for
     display because its old-style figures are the character of every big
     number on the site; Arial first for body as the accepted kit renders it;
     one mono stack that names Consolas before the generic so Windows renders
     the same face in every browser. */
  --font-display: Georgia, "Times New Roman", serif;
  --font-body: Arial, system-ui, -apple-system, sans-serif;
  --font-mono: ui-monospace, Menlo, Consolas, "Liberation Mono", monospace;
  --text-xs: 10px;
  --text-sm: 14px;
  --text-base: 16px;
  --text-lg: 20px;
  --leading-body: 1.6;
  --leading-tight: 1.1;

  /* rhythm */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --radius-sm: 8px;

  /* The ring must reach 3:1 against whatever sits beside it: the accent is
     3.54:1 on the page ground and 4.73:1 on the dark footer. */
  --focus-ring: 0 0 0 3px var(--accent);

  /* The motion floor. Interaction feedback everywhere on the site is a
     colour, border, underline, background or shadow that changes over
     --motion-fast; a state switch may fade over --motion-base. Nothing moves,
     nothing enters, nothing is keyframed. Family stylesheets apply these
     values to their own controls; reduced motion collapses all of it. */
  --motion-fast: 150ms;
  --motion-base: 200ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --transition-feedback:
    color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard),
    text-decoration-color var(--motion-fast) var(--ease-standard),
    box-shadow var(--motion-fast) var(--ease-standard);

  /* The publication frame: one container, one responsive gutter. */
  --container-max: 1200px;
  --gutter: 24px;

  /* Two strips stick at the top of a page: the masthead, on every page, and
     under it the page family's one horizontal local row where the family has
     one (the Numbers family row, the Projects and Council Record section
     row, the case studies' row of five). --mast-h is the masthead's height
     and --local-h the local row's (0 on a page without one); shell.js
     measures both as they wrap, and these are the no-script values.
     --chrome-h is their sum: every jump offset and every sticky rail reads
     that one property, so nothing else has to know how tall the stack is. */
  --mast-h: 73px;
  --local-h: 0px;
  --chrome-h: calc(var(--mast-h) + var(--local-h));

  /* dark-surface working values (footer, dark bands) — mixes of the tokens above */
  --on-dark:       color-mix(in oklab, var(--surface) 74%, var(--fg));
  --on-dark-quiet: color-mix(in oklab, var(--surface) 56%, var(--fg));
  --dark-border:   color-mix(in oklab, var(--surface) 14%, var(--fg));
  --dark-surface:  color-mix(in oklab, var(--surface) 8%, var(--fg));
  --dark-accent:   color-mix(in oklab, var(--accent) 74%, var(--surface));
}
@media (max-width: 900px) { :root { --gutter: 16px; --mast-h: 93px; } }
@media (max-width: 640px) { :root { --gutter: 12px; --mast-h: 105px; } }
/* The no-script height of a local row (all three are 46px rows); shell.js
   replaces it with the measured height on load. */
:root:has(.wf-famnav, .secnav, .cs-family) { --local-h: 46px; }

/* An in-page jump lands its target clear of the sticky stack — the masthead
   and the family's local row — with a breath. */
html { scroll-padding-top: calc(var(--chrome-h) + var(--space-4)); }

/* ── ground and vertical structure ───────────────────────────────────────
   The shell owns the page's vertical composition: a short page still reaches
   the bottom of the viewport with the footer at the foot. Families set their
   own body type; they do not set the ground. */
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
}
main { flex: 1 0 auto; }

/* ── container ──────────────────────────────────────────────────────────
   .w is the frame's container (padding-based). Legacy canvases use .wrap,
   which site.css keeps on the same metric so content edges align with the
   masthead and footer on every route. */
.w { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }

/* ── skip link and shell focus ─────────────────────────────────────────── */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--fg); color: var(--surface); padding: var(--space-2) var(--space-4);
  font-family: var(--font-body); font-size: var(--text-sm); text-decoration: none;
}
.skip:focus-visible { left: 0; color: var(--surface); }
/* One focus treatment for the controls the shell owns. Family stylesheets keep
   their own rules for the controls inside <main>. */
.skip:focus-visible, .wf-mast a:focus-visible, .wf-foot a:focus-visible {
  outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm);
}

/* ── masthead ─────────────────────────────────────────────────────────────
   Sticky on every page and at every width: the wordmark and the six
   destinations stay at the top while the page moves under them. The family's
   one horizontal local row sticks directly under it (top: var(--mast-h),
   one step lower in the paint order); the identity band scrolls away
   between them. The masthead has to stay short, and on a phone it tightens
   rather than growing a third row. */
.wf-mast {
  background: var(--bg); color: var(--fg); border-bottom: 1px solid var(--border-soft);
  position: sticky; top: 0; z-index: 30;
  font-family: var(--font-body); line-height: var(--leading-body);
}
.wf-mast-in { display: flex; align-items: center; justify-content: space-between; gap: var(--space-6); padding-block: var(--space-4); }
.wf-brand { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; color: var(--fg); flex: none;
  transition: var(--transition-feedback); }
/* Families style their own links; the wordmark is the shell's on every page. */
.wf-brand:hover, .wf-brand:focus-visible { color: var(--fg); }
.wf-brand img { width: 30px; height: auto; display: block; }
.wf-brand b { font-family: var(--font-display); font-weight: 500; font-size: var(--text-lg); white-space: nowrap; }
.wf-mast nav { display: flex; gap: var(--space-6); font-size: var(--text-sm); }
.wf-mast nav a {
  color: var(--muted); text-decoration: none; padding-block: var(--space-2); white-space: nowrap;
  display: inline-flex; align-items: center; min-height: 40px;
  transition: var(--transition-feedback);
}
.wf-mast nav a:hover { color: var(--fg); }
.wf-mast nav a[aria-current] { color: var(--fg); font-weight: 500; box-shadow: inset 0 -2px 0 var(--accent); }
/* The route rule above outranks the shell focus rule for box-shadow, so the
   current route states both: its rule and the ring. */
.wf-mast nav a[aria-current]:focus-visible { box-shadow: var(--focus-ring), inset 0 -2px 0 var(--accent); }
/* Below 900px the six destinations wrap under the wordmark. Every destination
   stays visible and reachable — no scroller, no hidden overflow, no menu. */
@media (max-width: 900px) {
  .wf-mast-in { flex-wrap: wrap; gap: var(--space-1) var(--space-6); padding-block: var(--space-2); }
  .wf-mast nav { width: 100%; flex-wrap: wrap; gap: 0 var(--space-5); }
  .wf-mast nav a { padding-block: var(--space-1); min-height: 36px; }
}
/* A phone: the wordmark a size down and the destinations on two tight rows,
   so the sticky strip stays near an eighth of the screen. */
@media (max-width: 640px) {
  .wf-mast-in { gap: 0 var(--space-4); padding-block: var(--space-2) var(--space-1); }
  .wf-brand { gap: var(--space-2); }
  .wf-brand img { width: 26px; }
  .wf-brand b { font-size: 18px; line-height: 1.4; }
  .wf-mast nav { gap: 0 var(--space-4); font-size: 13.5px; }
  .wf-mast nav a { padding-block: 0; min-height: 32px; }
}

/* ── identity band ────────────────────────────────────────────────────────
   The page-entry grammar every family shares (D-069): one primitive, three
   variants, one identity.
     default            dark text-led band (no photograph required)
     .wf-band--photo    photograph behind the same composition; the page
                        supplies the image as --wf-band-photo
     .wf-band--compact  working-mode strip for tool and record pages
   The terracotta rule underneath is the seam between the band and whatever
   the family's canvas does. Keep it. The band sets its own face, weight and
   leading so it renders identically over either family's body rules. */
.wf-band {
  background-color: var(--fg);
  background-size: cover; background-position: center 46%;
  border-bottom: 3px solid var(--accent);
  font-family: var(--font-body); line-height: var(--leading-body);
}
.wf-band--photo {
  background-image:
    linear-gradient(100deg,
      color-mix(in oklab, var(--fg) 88%, transparent) 0%,
      color-mix(in oklab, var(--fg) 70%, transparent) 52%,
      color-mix(in oklab, var(--fg) 46%, transparent) 100%),
    var(--wf-band-photo);
}
/* The same photograph delivered as an <img srcset> (identity_banner with
   photo_srcset), so a phone is not sent the 2000px file. The image fills the
   band under the same gradient, drawn by ::before; the composition stacks
   above both. The band's height is the page's to set; the image never sets
   it, so nothing shifts while it loads. */
.wf-band--photo.has-img { position: relative; overflow: hidden; background-image: none; }
.wf-band--photo.has-img .wf-band-img {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; display: block;
  object-fit: cover; object-position: center 46%;
}
.wf-band--photo.has-img::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background-image: linear-gradient(100deg,
    color-mix(in oklab, var(--fg) 88%, transparent) 0%,
    color-mix(in oklab, var(--fg) 70%, transparent) 52%,
    color-mix(in oklab, var(--fg) 46%, transparent) 100%);
}
.wf-band--photo.has-img .wf-band-in { position: relative; z-index: 2; }
/* Two levels of one hierarchy. Home's band is the tall hero (foundation.css
   sizes it); every other page carries the same photograph in a band the
   height of its own title, a shade darker so the title reads and the image
   stays subordinate — a modest step, not a blacked-out picture. */
.wf-band--page,
.wf-band--page.has-img::after {
  background-image: linear-gradient(100deg,
    color-mix(in oklab, var(--fg) 93%, transparent) 0%,
    color-mix(in oklab, var(--fg) 80%, transparent) 52%,
    color-mix(in oklab, var(--fg) 62%, transparent) 100%);
}
.wf-band--page .wf-band-img { object-position: center 40%; }
.wf-band-in {
  padding-block: clamp(28px, 4.6vw, 52px);
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-8); flex-wrap: wrap;
}
.wf-band .kicker {
  margin: 0; font-size: 12px; font-weight: 500; letter-spacing: 0.12em; text-transform: uppercase;
  color: color-mix(in oklab, var(--accent) 64%, var(--surface));
}
.wf-band h1 {
  margin: var(--space-3) 0 0; font-family: var(--font-display); font-weight: 500;
  font-size: clamp(30px, 4.4vw, 46px); line-height: var(--leading-tight); text-wrap: balance;
  letter-spacing: -0.02em; color: var(--surface); max-width: 20ch;
}
/* One line under the title, in the band's own voice: quieter than the title
   and louder than the meta, on the same measure so it breaks with it. */
.wf-band .band-stand {
  margin: var(--space-3) 0 0; font-size: var(--text-lg); line-height: var(--leading-body);
  color: color-mix(in oklab, var(--surface) 82%, var(--fg)); max-width: 34ch;
}
.wf-band .band-meta {
  margin: 0; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
  color: color-mix(in oklab, var(--surface) 62%, var(--fg));
  line-height: 1.9; text-align: right;
}
.wf-band .band-meta b { color: var(--surface); font-weight: 500; }
/* A photograph from outside the publication carries its credit under the
   caption: sentence case, quieter than the caption, still readable. */
.wf-band .band-aside { text-align: right; }
.wf-band .band-credit {
  margin: var(--space-1) 0 0; font-size: 12px; line-height: 1.5; letter-spacing: 0.01em;
  color: color-mix(in oklab, var(--surface) 70%, var(--fg));
  /* On a phone the credit can cross the bright truss; a soft ink shadow
     keeps it legible without darkening the photograph. */
  text-shadow: 0 1px 2px color-mix(in oklab, var(--fg) 70%, transparent);
}
.wf-band .band-credit a { color: inherit; text-decoration: underline; text-underline-offset: 2px;
  text-decoration-color: color-mix(in oklab, var(--surface) 40%, var(--fg)); }
.wf-band .band-credit a:hover { color: var(--surface); }
@media (max-width: 640px) { .wf-band .band-meta, .wf-band .band-aside { text-align: left; } }

/* A record page's title is a matter or a claim, longer than a section name;
   the compact variant lets it run to a sentence rather than stacking it. It
   shares the page band's height: one secondary-page header, not a third. */
.wf-band--compact h1 { margin-top: var(--space-1); font-size: clamp(20px, 2.4vw, 26px); max-width: 36ch; }
.wf-band--compact .band-meta { line-height: 1.6; }

/* ── editorial plates ─────────────────────────────────────────────────────
   The ten editorial illustrations (app/editorial.py) are interpretive
   artwork, never evidence. They are set as plates: the whole picture at its
   own 4:3, square-cornered on a hairline, never cropped into a banner and
   never behind text. Both families use them, so the grammar is the shell's.
   .wf-withplate sets one to the left of a block of text; on a phone .is-flow
   lets long text run round the picture instead of stacking it on top. */
.wf-plate { margin: 0; }
.wf-plate picture, .wf-plate img { display: block; }
.wf-plate img {
  width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
  background: var(--surface-warm); border: 1px solid var(--border-soft);
}
.wf-plate figcaption { margin-top: var(--space-2); font-family: var(--font-body);
  font-size: 12px; line-height: 1.45; color: var(--meta); }
.wf-withplate {
  display: grid; align-items: start;
  grid-template-columns: minmax(0, var(--plate-w, 300px)) minmax(0, 1fr);
  gap: var(--space-5) clamp(20px, 3vw, 40px);
}
.wf-withplate > * { min-width: 0; }
@media (max-width: 640px) {
  .wf-withplate { grid-template-columns: minmax(0, 36%) minmax(0, 1fr); column-gap: var(--space-4); }
  .wf-withplate.is-flow { display: flow-root; }
  .wf-withplate.is-flow > .wf-plate { float: left; width: 40%; margin: var(--space-1) var(--space-4) var(--space-2) 0; }
}

/* ── latest and next meeting ──────────────────────────────────────────────
   The Council Record's Latest/Next strip (_council_record.html
   orientation_strip), drawn on the Council Record landing and on Home: two
   cells on one rule, a label, a title line, a meta line and the actions. It
   lives in the shell because both families draw it, in the shell's tokens
   so it is the same strip on either canvas. The next cell is a scheduled
   date first and a document second, and its basis (which minutes stated
   the date) is a quiet line under the actions. */
.cr-orient { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 clamp(24px, 4vw, 48px);
  margin: 0; padding: var(--space-4) 0 var(--space-4); border-top: 1px solid var(--fg-2); border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-body); line-height: var(--leading-body); }
.cr-orient-cell { min-width: 0; }
.cr-orient-cell + .cr-orient-cell { border-left: 1px solid var(--border-soft); padding-left: clamp(20px, 3vw, 40px); }
.cr-orient .cr-h { margin: 0 0 var(--space-2); font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.cr-orient-v { margin: 0 0 var(--space-1); font-family: var(--font-display); font-weight: 500; font-size: clamp(19px, 1.7vw, 22px); line-height: 1.3; color: var(--fg); }
.cr-orient-v a { color: inherit; text-decoration: none; }
.cr-orient-v a:hover { color: var(--accent-active); }
.cr-orient-m { margin: 0; font-size: var(--text-sm); color: var(--fg-2); }
.cr-orient-a { margin: var(--space-2) 0 0; display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); align-items: baseline; font-size: var(--text-sm); }
.cr-orient-a .card-link { display: inline-flex; align-items: center; gap: 0.35em; font-weight: 600; text-decoration: none;
  color: var(--fg-2); border-bottom: 1px solid currentColor; padding-bottom: 1px; }
.cr-orient-a .card-link:hover { color: var(--fg); border-bottom-width: 2px; }
.cr-orient-basis { flex-basis: 100%; font-size: 13px; color: var(--muted); }
.cr-orient-basis a { color: inherit; }
@media (max-width: 640px) {
  .cr-orient { grid-template-columns: minmax(0, 1fr); gap: var(--space-4) 0; }
  .cr-orient-cell + .cr-orient-cell { border-left: 0; padding-left: 0; border-top: 1px dotted var(--border-soft); padding-top: var(--space-4); }
}

/* ── the five case studies ────────────────────────────────────────────────
   One row naming every case study, directly under the band on the Case
   Studies index and on each study (marking that one), the way Projects &
   Consultations carries its section row. It is a sibling set, not a
   hierarchy, so it is a row of names and not a menu. It lives in the shell
   because the index is a foundation page and a study is not. Below 900px it
   scrolls sideways under a fade rather than wrapping. It is the case
   studies' local row, so it sticks under the masthead on an opaque ground. */
.cs-family { border-bottom: 1px solid var(--border-soft); background: var(--bg);
  position: sticky; top: var(--mast-h); z-index: 29;
  font-family: var(--font-body); line-height: var(--leading-body); }
.cs-family .cs-family-in { display: flex; align-items: stretch; gap: clamp(18px, 2.4vw, 32px);
  overflow-x: auto; scrollbar-width: none; overscroll-behavior-inline: contain; }
.cs-family .cs-family-in::-webkit-scrollbar { display: none; }
.cs-family .cs-family-in a {
  flex: none; padding-block: var(--space-3); text-decoration: none;
  font-size: 12px; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--muted); border-bottom: 2px solid transparent; white-space: nowrap;
  transition: var(--transition-feedback);
}
.cs-family .cs-family-in a:hover { color: var(--fg-2); }
.cs-family .cs-family-in a[aria-current="page"] { color: var(--fg); border-bottom-color: var(--accent); font-weight: 500; }
/* Inside the scroller the ring would be clipped; draw it inset. */
.cs-family .cs-family-in a:focus-visible { outline: none; border-radius: 0; box-shadow: inset 0 0 0 3px var(--accent); }
.cs-family .cap { flex: none; align-self: center; padding-right: var(--space-2);
  font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
@media (max-width: 900px) {
  .cs-family .cs-family-in {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent);
  }
  .cs-family .cs-family-in::after { content: ""; flex: none; width: 2rem; }
}
@media (max-width: 640px) { .cs-family .cap { display: none; } }

/* ── footer ───────────────────────────────────────────────────────────── */
.wf-foot {
  background: var(--fg); color: var(--on-dark-quiet); border-top: 1px solid var(--dark-border);
  padding-block: clamp(40px, 5vw, 64px) var(--space-8);
  font-family: var(--font-body); font-size: var(--text-sm); line-height: var(--leading-body);
}
/* The site's sourcing principle, once, in the display face: a quiet line
   above the links, not a disclaimer. The long form is on Sources. */
.wf-foot .wf-foot-principle { margin: 0 0 var(--space-5); max-width: 44ch;
  font-family: var(--font-display); font-size: 18px; line-height: 1.4; color: var(--on-dark); }
.wf-foot-links { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-8); }
.wf-foot-links a { display: inline-block; padding-block: 3px; text-decoration: none; color: var(--on-dark-quiet);
  transition: var(--transition-feedback); }
.wf-foot-links a:hover { color: var(--surface); }
@media (max-width: 640px) { .wf-foot-links a { padding-block: var(--space-2); } }
.wf-foot .fine {
  margin: clamp(20px, 3vw, 32px) 0 0; padding-top: var(--space-5);
  border-top: 1px solid var(--dark-border); max-width: 78ch; font-size: 13px; line-height: 1.7;
  /* 13px text on the dark footer: the quiet-on-dark token reads 5.3:1. */
  color: var(--on-dark-quiet);
}
.wf-foot .buildline { margin: var(--space-4) 0 0; font-family: var(--font-mono); font-size: 12px;
  letter-spacing: 0.02em; color: color-mix(in oklab, var(--surface) 32%, var(--fg)); }

@media (prefers-reduced-motion: reduce) {
  .wf-brand, .wf-mast nav a, .wf-foot-links a { transition: none; }
}
/* ── the forward path ────────────────────────────────────────────────────
   Every substantive page ends with one quiet link to the next page in the
   site's reading order (app/site_sequence.py): the destination's own title
   and an arrow, at the foot on the right, after the last content or evidence
   section. It is a link, not a card, a banner or a call to action. */
.wf-next .w { display: flex; justify-content: flex-end; padding-block: var(--space-8) var(--space-12); }
.wf-next a {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: 44px;
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;
  color: var(--fg); text-decoration: none;
  border-bottom: 2px solid var(--accent); padding-block: var(--space-1);
  transition: var(--transition-feedback);
}
.wf-next a:hover { color: var(--accent-active); }
.wf-next a:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }

/* ── back to top ─────────────────────────────────────────────────────────
   One fixed control for every family, in the markup with `hidden` so a
   reader without scripting is never shown a control that cannot work
   (static/js/shell.js). It fades in a screen down a long page and out again
   at the foot, where the forward link above already is, so the two never sit
   on top of each other. Nothing moves; only opacity changes. */
.wf-top {
  position: fixed; right: var(--gutter); bottom: var(--gutter); z-index: 40;
  width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-soft); border-radius: 999px;
  background: var(--surface); color: var(--fg-2);
  font-family: var(--font-body); font-size: 17px; line-height: 1; cursor: pointer;
  box-shadow: 0 1px 3px color-mix(in oklab, var(--fg) 14%, transparent);
  opacity: 0; visibility: hidden;
  transition: opacity var(--motion-base) var(--ease-standard),
    visibility var(--motion-base) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
.wf-top[hidden] { display: none; }
.wf-top.is-on { opacity: 1; visibility: visible; }
.wf-top:hover { color: var(--fg); border-color: var(--muted); }
.wf-top:focus-visible { outline: none; box-shadow: var(--focus-ring); opacity: 1; visibility: visible; }
/* The map application fills the viewport and owns its own bottom-right
   corner (attribution, the locate control), so the page controls stand down. */
:root:has(.xp-app) .wf-top, :root:has(.xp-app) .wf-next { display: none; }
@media (max-width: 640px) { .wf-top { width: 48px; height: 48px; } }

@media print {
  .wf-mast nav, .skip, .wf-top, .wf-next { display: none; }
  .wf-mast { position: static; }
  body { background: none; }
  .wf-band { background-image: none; background-color: transparent; border-bottom: 2px solid var(--fg); }
  .wf-band--photo.has-img .wf-band-img, .wf-band--photo.has-img::after { display: none; }
  .wf-band h1, .wf-band .kicker, .wf-band .band-meta, .wf-band .band-meta b { color: var(--fg); }
  .wf-foot, .wf-foot-links a, .wf-foot .fine { background: none; color: var(--muted); border-color: var(--border-soft); }
}
/* Forced colours drop box-shadows, which carry both the ring and the route rule. */
@media (prefers-reduced-motion: reduce) {
  .wf-top { transition: none; }
}
@media (forced-colors: active) {
  .skip:focus-visible, .wf-mast a:focus-visible, .wf-foot a:focus-visible,
  .wf-top:focus-visible, .wf-next a:focus-visible { outline: 3px solid CanvasText; outline-offset: 2px; }
  .wf-mast nav a[aria-current] { text-decoration: underline; text-decoration-thickness: 2px; }
}
