/* ==========================================================================
   components.css — every reusable component, built once and documented on
   /styleguide.html. Phase 1 ships the button, the wordmark and provisional
   chrome; Phase 2 replaces the chrome and Phase 11 completes the states.
   ========================================================================== */

/* ---- BUTTON --------------------------------------------------------------
   Three weights (solid, outline, ghost) and four states (rest, hover, active,
   disabled), plus a focus ring inherited from base.css. */

.btn {
  --btn-bg: var(--c-pitch);
  --btn-fg: var(--c-text-on-brand);
  --btn-bd: var(--c-pitch);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  border: var(--bw-thin) solid var(--btn-bd);
  border-radius: var(--r-sm);
  background-color: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: var(--fw-black);
  line-height: 1.1;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              transform var(--dur-instant) var(--ease-out);
}

/* The :not() keeps hover off a button wearing a "coming soon" band. Those are
   spans, so they are not interactive, but a span still matches :hover and would
   otherwise light up under the mouse as though it could be pressed. Excluding
   them here, rather than restating the resting colours in a later rule, leaves
   each one at whatever colour it already has: they do not all sit on the same
   background, and an override would have had to pick one palette for all. */
.btn:hover:not(.is-coming-soon) {
  --btn-bg: color-mix(in srgb, var(--c-pitch) 82%, var(--c-ink));
  --btn-bd: var(--btn-bg);
  color: var(--btn-fg);
}
.btn:active { transform: translateY(1px); }

.btn[aria-disabled="true"],
.btn:disabled {
  --btn-bg: var(--c-disabled-bg);
  --btn-bd: var(--c-disabled-bg);
  --btn-fg: var(--c-disabled-fg);
  cursor: not-allowed;
  transform: none;
}

/* Weight 2: outline */
.btn--outline {
  --btn-bg: transparent;
  --btn-fg: var(--c-text);
  --btn-bd: var(--c-border-strong);
}
.btn--outline:hover {
  --btn-bg: var(--c-hover-wash);
  --btn-bd: var(--c-pitch);
  --btn-fg: var(--c-text);
}

/* Weight 3: ghost */
.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--c-text);
  --btn-bd: transparent;
}
.btn--ghost:hover {
  --btn-bg: var(--c-hover-wash);
  --btn-bd: transparent;
  --btn-fg: var(--c-text);
}

/* The persistent call to action. */
.btn--accent {
  --btn-bg: var(--c-floodlight);
  --btn-fg: var(--c-text-on-accent);
  --btn-bd: var(--c-floodlight);
}
.btn--accent:hover:not(.is-coming-soon) {
  --btn-bg: color-mix(in srgb, var(--c-floodlight) 84%, var(--c-ink));
  --btn-bd: var(--btn-bg);
  --btn-fg: var(--c-text-on-accent);
}

.btn--sm { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-2xs); }
.btn--lg { padding: var(--sp-4) var(--sp-6); font-size: var(--fs-base); }
.btn--block { display: flex; width: 100%; }

/* Selected state, used by the theme toggle and chart controls. */
.btn[aria-pressed="true"] {
  --btn-bg: var(--c-selected);
  --btn-bd: var(--c-border-strong);
  --btn-fg: var(--c-text);
}

/* ---- NOT OPEN YET --------------------------------------------------------
   Worn by a button whose feature is not available yet. In the
   markup that button is a <span>, not a link: there is no href to follow, and
   nothing for a keyboard or a screen reader to land on. This only dresses it.

   The band is a pseudo-element, so the words "Coming soon" are decoration and
   stay out of the markup — the accessible copy is a visually hidden phrase
   inside the button itself, which is what a screen reader reads.

   --c-surface-invert rather than --c-ink for the band: --c-ink inverts with the
   theme and would turn the band pale in dark mode, putting white text on it.

   The band is part-transparent so the button's own wording still reads through
   it, and the two requirements pull against each other: the more solid the
   band, the better "Coming soon" reads and the less the button's own label shows.
   The white band text needs 4.5:1 against the veil; the wording showing
   through needs 3:1. 40% failed the first and 55% failed the second, so the
   veil sits at 51%. See --c-stamp-veil in tokens.css for why one figure covers
   both themes. */
.btn.is-coming-soon {
  position: relative;
  overflow: hidden;
  cursor: default;
}

/* The band is clipped to the button, so its tilt has to suit the button's
   shape. Across a narrow header button a 9-degree sweep rises about 20px over
   the width and reads as a stamp. Across the full-width drawer button it would
   rise 56px inside a 43px button, and the "band" becomes a wedge covering the
   whole face. The wider the button, the shallower the tilt has to be. */
.btn--block.is-coming-soon { --stamp-tilt: -3deg; }

.btn.is-coming-soon::after {
  content: "Coming soon";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  inline-size: 180%;
  translate: -50% -50%;
  rotate: var(--stamp-tilt, -9deg);
  padding-block: 0.3em;
  background-color: var(--c-stamp-veil);
  color: var(--c-text-on-dark);
  font-size: 0.78em;
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-caps);
  text-align: center;
  text-transform: uppercase;
  pointer-events: none;
}

/* ---- SUPPORT COUNTER -----------------------------------------------------
   The button is a real form posting to act/support.php, so it works without
   JavaScript. The form is only a wrapper and must not take up space of its
   own or break the flex rows it sits inside, hence inline-flex and no margin
   rather than the block box a form gets by default.

   display: contents would be tidier still, and is not used: it removes the
   element's box from the layout and, in several browsers, the form from the
   accessibility tree with it. */
.support {
  display: inline-flex;
  margin: 0;
}

/* Pressed. aria-disabled rather than disabled, so the button can still be
   reached and read out, which means the styling has to come from the attribute
   rather than from :disabled.

   That attribute already carries the stylesheet's own unavailable-control
   treatment: a pale grey ground with grey lettering. On this button it measured
   3.79:1, under the 4.5:1 floor, and the opacity it used to carry here made it
   worse by washing both toward the header behind them. So the accent colours
   are put back and the opacity is gone: the pressed button keeps the contrast
   of any other accent button, and the word "Thank you" is what says it is done.

   Three classes and an attribute, because the rule it has to beat is
   .btn[aria-disabled="true"] and that already has two. */
/* A tick on the pressed button. The wording alone was not enough: people read
   "Thank you" as a greeting on a button rather than a receipt, pressed it
   again, and when nothing happened concluded it had not worked. A mark that
   only ever appears after the press is the fastest way to say "this is done"
   without reading anything. */
.support .btn[aria-disabled="true"] [data-support-label]::before {
  content: "\2713\00a0";
  font-weight: var(--fw-black);
}

.support .btn[aria-disabled="true"],
.support .btn[aria-disabled="true"]:hover {
  --btn-bg: var(--c-floodlight);
  --btn-bd: var(--c-floodlight);
  --btn-fg: var(--c-text-on-accent);
  cursor: default;
}


/* ---- THE THANK-YOU DIALOG ------------------------------------------------
   A real <dialog>. The browser centres it, puts it in the top layer above
   everything regardless of z-index, and draws the backdrop, so none of that is
   written out here.

   A dialog has a browser default border and padding that differ between
   engines, and a default max-width that is narrower than this content wants,
   so those are set rather than inherited. */
.support-modal {
  max-inline-size: min(34rem, calc(100vw - 2rem));
  padding: 0;
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-md);
  background-color: var(--c-surface);
  color: var(--c-text);
}
.support-modal::backdrop {
  background-color: color-mix(in srgb, var(--c-surface-invert) 62%, transparent);
}

.support-modal__inner { padding: var(--sp-5); }
.support-modal__inner > * + * { margin-block-start: var(--sp-4); }

.support-modal__title {
  margin: 0;
  font-size: var(--fs-lg);
  line-height: var(--lh-tight);
}

/* A fieldset carries a border and padding by default that would draw a second
   box inside the dialog. */
.support-modal__kinds {
  margin: 0;
  padding: 0;
  border: 0;
}
.support-modal__kinds p { margin-block: var(--sp-3); }

/* The whole line is the target, not just the dot: easier to hit on a phone and
   for anyone who does not aim precisely. */
.support-modal__kinds label {
  display: flex;
  gap: var(--sp-3);
  align-items: flex-start;
  cursor: pointer;
}
.support-modal__kinds input {
  flex-shrink: 0;
  margin-block-start: 0.2em;
  inline-size: 1.1em;
  block-size: 1.1em;
  accent-color: var(--c-pitch);
}

.support-modal__small {
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}

/* Two buttons that do opposite things. Wrapping rather than shrinking, so
   "Cancel my support" keeps its full wording on a narrow phone instead of
   being squeezed into something that reads like "Cancel". */
.support-modal__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  justify-content: flex-end;
}

/* Only appears if a press could not be counted. */
.support__error {
  margin-block-start: var(--sp-2);
  color: var(--c-warn);
  font-size: var(--fs-xs);
}

/* ---- WORDMARK ------------------------------------------------------------ */

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  color: var(--c-text);
  text-decoration: none;
}
/* The lockup is a raster image now, not the hand-drawn symbol, so it cannot be
   recoloured by custom properties. Two files carry what one SVG used to:
   wordmark.png as drawn, and wordmark-reversed.png with the lettering taken to
   paper ink for dark grounds. The footer and the mobile overlay are dark in
   both themes and use the reversed file outright. Only the header changes with
   the theme, which is why it ships both and hides one. */
.wordmark__img {
  display: block;
  max-width: 100%;
}

.wordmark__img--dark { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wordmark__img--light { display: none; }
  :root:not([data-theme="light"]) .wordmark__img--dark { display: block; }
}
:root[data-theme="dark"] .wordmark__img--light { display: none; }
:root[data-theme="dark"] .wordmark__img--dark { display: block; }

/* The lockup keeps the width its band gives it. Without this it is the only
   thing in the bar that can shrink — the nav items are nowrap — so between
   900px and 1200px the flex algorithm was taking the whole deficit out of the
   logo and rendering it at 83px, whatever width was declared. Every band below
   therefore states a width, because with shrinking off there is no fallback. */
.site-header .wordmark { flex-shrink: 0; }

@media (max-width: 30rem) {
  .site-header .wordmark__img { width: 140px; }
}

/* Above the phone breakpoint the nav is still behind the menu button, so the
   bar is nearly all lockup and it can scale with the viewport. */
@media (min-width: 30.0625rem) and (max-width: 56.1875rem) {
  .site-header .wordmark__img { width: clamp(160px, 24vw, 195px); }
}

/* The lockup is the identity, so above the single-row breakpoint it is given
   real size. At the supplied artwork's ratio of 940:324, 290px wide is 100px
   tall, which the 7rem bar holds with room to breathe.
   The nav pays for it. Six items and a call to action will not fit beside a
   290px lockup at their full size, so above this breakpoint they take the same
   tightening the 900-1200 band already applies: smaller caps, less padding,
   narrower gaps. That is the trade the wider lockup is worth. */
@media (min-width: 75rem) {
  .site-header .wordmark__img { width: 290px; }
  .site-header__inner { gap: var(--sp-3); }
  .site-header__end { gap: var(--sp-2); }
  .site-header .nav__trigger,
  .site-header .nav__link {
    gap: var(--sp-1);
    padding-inline: var(--sp-2);
    font-size: var(--fs-2xs);
  }
  .site-header .nav__chev { width: 11px; height: 11px; }
  .site-header__cta { padding-inline: var(--sp-3); font-size: var(--fs-2xs); }
}

/* ---- SVG SPRITE ----------------------------------------------------------
   Symbols referenced by <use>. Must not be display:none, or some engines
   refuse to render the referenced symbol. */

.svg-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ==========================================================================
   SITE HEADER
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background-color: var(--c-paper);
  border-bottom: var(--bw-hair) solid var(--c-border);
  transition: box-shadow var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}

/* Elevation change after 80px, added by nav.js. */
.site-header.is-scrolled {
  box-shadow: var(--shadow-header);
  border-bottom-color: transparent;
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-height: var(--header-h);
}

.site-header__end {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-inline-start: auto;
}

.site-header__cta {
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-2xs);
  white-space: nowrap;
}

.site-header__count {
  padding-inline-start: var(--sp-2);
  border-inline-start: var(--bw-hair) solid currentColor;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}

/* ---- The hamburger -------------------------------------------------------
   Hidden in the markup and revealed by nav.js below 900px, so a reader
   without JavaScript never meets a button that does nothing. */

.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-sm);
  color: var(--c-text);
}
.nav__toggle:hover { background-color: var(--c-hover-wash); }
.nav__toggle[hidden] { display: none; }

/* ==========================================================================
   NAVIGATION

   Same markup, two presentations. The plain links are what a reader without
   JavaScript sees; nav.js swaps in the buttons by adding .js to <html>
   (set inline in the head, so there is no flash), and puts the links back
   if it fails to start.
   ========================================================================== */

.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav__link,
.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--c-text);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.nav__link:hover,
.nav__trigger:hover { background-color: var(--c-hover-wash); color: var(--c-text); }

/* The swap. */
.nav__trigger { display: none; }
.js .nav__trigger { display: inline-flex; }
.js .nav__link { display: none; }
.nav-fallback .nav__trigger { display: none; }
.nav-fallback .nav__link { display: inline-flex; }

.nav__chev {
  transition: transform var(--dur-fast) var(--ease-out);
  opacity: 0.7;
}
[data-open] > .nav__trigger .nav__chev { transform: rotate(180deg); }

[data-open] > .nav__trigger {
  background-color: var(--c-surface-3);
  box-shadow: inset 0 calc(-1 * var(--bw-thick)) 0 var(--c-floodlight);
}

/* ---- Mega-menu panel (>= 900px) ----------------------------------------- */

.nav__panel {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: var(--z-panel);
  background-color: var(--c-surface-2);
  border-block: var(--bw-hair) solid var(--c-border);
  box-shadow: var(--shadow-3);
}
.nav__panel[hidden] { display: none; }

@media (prefers-reduced-motion: no-preference) {
  .nav__panel:not([hidden]) {
    animation: nav-panel-in var(--dur-fast) var(--ease-out);
  }
}
@keyframes nav-panel-in {
  from { opacity: 0; transform: translateY(-0.35rem); }
  to   { opacity: 1; transform: none; }
}

.nav__panel-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
  gap: var(--sp-7);
  padding-block: var(--sp-6);
}

.nav__panel-title {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
  margin-bottom: var(--sp-4);
}

.nav__sublist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--sp-2) var(--sp-6);
  list-style: none;
  padding: 0;
  margin: 0;
}
.nav__sublist a {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  margin-inline-start: calc(-1 * var(--sp-3));
  border-radius: var(--r-sm);
  color: var(--c-text);
  font-size: var(--fs-base);
  text-decoration: none;
}
.nav__sublist a:hover {
  background-color: var(--c-hover-wash);
  color: var(--c-text);
  text-decoration: underline;
}
.nav__sublist li:first-child a { font-weight: var(--fw-bold); }

.nav__feature {
  padding: var(--sp-4);
  background-color: var(--c-surface);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}
.nav__feature > * + * { margin-top: var(--sp-3); }

.nav__feature-kicker {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
}
.nav__feature-blurb { font-size: var(--fs-sm); color: var(--c-text); }
.nav__feature-note { font-size: var(--fs-2xs); }

.nav__feature-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-link);
}

/* The miniature ladder in the Pyramid panel. Seven rungs, widening as they
   descend: the argument in one graphic. Works with no JavaScript at all. */
.mini-ladder { list-style: none; padding: 0; margin: 0; }
.mini-ladder a {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding-block: var(--sp-1);
  font-size: var(--fs-xs);
  color: var(--c-text);
  text-decoration: none;
}
.mini-ladder a:hover { color: var(--c-link); text-decoration: underline; }
.mini-ladder__rung {
  display: block;
  block-size: 0.5rem;
  inline-size: calc(1.6rem + (var(--rung) * 1.5rem));
  background-color: var(--c-pitch);
  border-radius: var(--r-xs);
  opacity: calc(0.45 + (var(--rung) * 0.08));
}

/* Hide the mobile-only furniture on desktop. */
.site-nav__head,
.site-nav__cta { display: none; }

/* ---- Mobile overlay (< 900px) ------------------------------------------- */

@media (max-width: 56.24rem) {
  /* Without JavaScript the nav is a plain stacked list under the wordmark:
     no overlay, no buttons, nothing that needs script to work. */
  html:not(.js) .site-nav__list,
  .nav-fallback .site-nav__list {
    flex-direction: column;
    align-items: flex-start;
    inline-size: 100%;
    padding-block: var(--sp-3);
  }
  html:not(.js) .site-header__inner,
  .nav-fallback .site-header__inner { flex-wrap: wrap; }

  .js .site-nav {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-gutter) var(--sp-7);
    background-color: var(--c-paper);
    overflow-y: auto;
    overscroll-behavior: contain;
    visibility: hidden;
    transform: translateX(100%);
    transition: transform var(--dur-base) var(--ease-out),
                visibility 0s linear var(--dur-base);
  }
  .js .site-nav[data-open] {
    visibility: visible;
    transform: none;
    transition: transform var(--dur-base) var(--ease-out), visibility 0s;
  }
  .nav-fallback .site-nav {
    position: static;
    visibility: visible;
    transform: none;
    padding: 0;
    overflow: visible;
  }

  .js .site-nav__head,
  .js .site-nav__cta { display: flex; }
  .js .site-nav__head {
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding-block-end: var(--sp-4);
    border-bottom: var(--bw-hair) solid var(--c-border);
  }

  .js .site-nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .js .nav__item { border-bottom: var(--bw-hair) solid var(--c-border); }

  .js .nav__trigger {
    inline-size: 100%;
    justify-content: space-between;
    padding-block: var(--sp-4);
    font-size: var(--fs-md);
    border-radius: 0;
  }
  .js [data-open] > .nav__trigger { box-shadow: none; background: none; }

  /* Accordion, not overlay-within-overlay. */
  .js .nav__panel {
    position: static;
    background: none;
    border: 0;
    box-shadow: none;
    animation: none;
  }
  .js .nav__panel-inner {
    display: block;
    padding: 0 0 var(--sp-4);
    max-width: none;
  }
  .js .nav__panel-title { display: none; }
  .js .nav__sublist { display: block; }
  .js .nav__sublist a { padding-block: var(--sp-3); }
  .js .nav__feature { margin-top: var(--sp-4); }

  .js .site-nav__cta { margin-top: auto; padding-top: var(--sp-4); }

}

@media (min-width: 56.25rem) {
  .site-nav { display: flex; align-items: center; }

  /* Six triggers, a wordmark and a call to action share one row. That row
     must never wrap: a wrapped header doubles in height, and because it is
     sticky it would eat a second row of the viewport on every page. */
  .site-nav__list { flex-wrap: nowrap; }
}

/* Between 900px and 1200px there is not enough room at full size, so the
   whole bar tightens rather than wrapping. */
/* Very narrow phones. At 320px the lockup, the support button and the menu
   button do not fit at their normal sizes: the row ran 40px over and pushed
   the menu button off the screen entirely, leaving no way to navigate. The
   button is what has to give, not the menu. */
@media (max-width: 26.25rem) {
  .site-header__inner { gap: var(--sp-2); }
  .site-header__end { gap: var(--sp-2); }
  .site-header .wordmark__img { width: clamp(112px, 34vw, 140px); }
  .site-header__cta {
    padding-inline: var(--sp-2);
    font-size: var(--fs-2xs);
    letter-spacing: 0;
  }
}

@media (min-width: 56.25rem) and (max-width: 74.9375rem) {
  .site-header__inner { gap: var(--sp-2); }
  /* Six nav items and the call to action are nowrap and take ~734px of the
     row here, so this is what is genuinely left rather than what we would
     like. It scales with the viewport because the room appears gradually. */
  .site-header .wordmark__img { width: clamp(120px, 13vw, 190px); }
  .nav__trigger {
    gap: var(--sp-1);
    padding-inline: var(--sp-2);
    font-size: var(--fs-2xs);
  }
  .nav__chev { width: 11px; height: 11px; }
  .site-header__cta { padding-inline: var(--sp-3); font-size: var(--fs-2xs); }
}

/* ==========================================================================
   BREADCRUMBS
   ========================================================================== */

.breadcrumbs {
  border-bottom: var(--bw-hair) solid var(--c-border);
  padding-block: var(--sp-3);
  font-size: var(--fs-xs);
}
.breadcrumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  list-style: none;
  padding: 0;
  margin: 0;
}
.breadcrumbs__list li { display: flex; align-items: center; gap: var(--sp-2); }
.breadcrumbs__list li + li::before {
  content: "/";
  color: var(--c-text-faint);
}
.breadcrumbs [aria-current="page"] { color: var(--c-text-muted); }

/* main is focusable for the skip link but must never show a ring on click. */
.page__main:focus { outline: none; }

/* ==========================================================================
   SITE FOOTER
   ========================================================================== */

.site-footer {
  margin-top: var(--sp-section);
  padding-block: var(--sp-8) var(--sp-6);
  /* The dark slab in both themes, so the amber links keep their contrast.
     In dark mode it sits only a shade below the page, hence the rule on top. */
  border-top: var(--bw-thick) solid var(--c-floodlight);
  background-color: var(--c-surface-invert);
  color: var(--c-text-invert);
  font-size: var(--fs-sm);
}
/* :not(.btn) — see the note on .section--brand a in layout.css. */
.site-footer a:not(.btn) { color: var(--c-floodlight); }
.site-footer a:not(.btn):hover { color: var(--c-text-invert); }
.site-footer :is(h2, h3) { color: var(--c-text-invert); }

.site-footer__cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--sp-7) var(--sp-6);
}

@media (min-width: 62rem) {
  .site-footer__cols {
    grid-template-columns: 1.1fr 2fr 1fr 1fr;
  }
}

.site-footer__col > * + * { margin-top: var(--sp-4); }

.site-footer__heading {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
}

.site-footer__about p { color: color-mix(in srgb, var(--c-text-invert) 82%, transparent); }
.site-footer__note {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  color: var(--c-floodlight) !important;
}

.site-footer__sitemap-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr));
  gap: var(--sp-5) var(--sp-4);
}
.site-footer__sitemap h3 {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: color-mix(in srgb, var(--c-text-invert) 62%, transparent);
  margin-bottom: var(--sp-2);
}
.site-footer__sitemap li + li { margin-top: var(--sp-1); }

.site-footer__count {
  font-family: var(--font-display);
  line-height: var(--lh-tight);
}
.site-footer__count[hidden] { display: none; }
.site-footer__count-value {
  display: block;
  font-size: var(--fs-2xl);
  color: var(--c-floodlight);
  font-variant-numeric: tabular-nums;
}
.site-footer__count-label {
  font-family: var(--font-text);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
}

.site-footer__contactlist li + li { margin-top: var(--sp-3); }
.site-footer__contactlist .u-caps {
  color: color-mix(in srgb, var(--c-text-invert) 62%, transparent);
}
.site-footer__social { --cluster-gap: var(--sp-4); }

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-3) var(--sp-6);
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: var(--bw-hair) solid color-mix(in srgb, var(--c-text-invert) 25%, transparent);
  font-size: var(--fs-xs);
  color: color-mix(in srgb, var(--c-text-invert) 78%, transparent);
}
.site-footer__legal { display: flex; flex-wrap: wrap; gap: var(--sp-4); }
/* The promise shares the copyright's row. At the smallest size, with the caps
   tracking eased, the row needs about 1,090px, and it has 1,136px from 75rem.
   Only there is it pushed to the right edge; narrower, it follows the legal
   links if they leave room and otherwise starts its own line at the left,
   so the base reads as a stacked list rather than a line with an orphan
   hanging off its right end. */
.site-footer__promise {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--c-text-invert);
}
@media (min-width: 75rem) {
  .site-footer__promise { margin-inline-start: auto; }
}

/* Design credit. Its own line at the foot of the base row, so that adding it
   reflows neither the copyright, the legal links nor the promise.

   The founded.ai mark keeps its own colours, as the Fair Share wordmark does:
   it is somebody else's identity, not a themed element. Only the lettering
   is reversed, so the lockup stays legible on the dark ground.

   The logo carries the name by itself: the line reads "Site designed by" and
   then the lockup. So the image is not decorative and its alt text names the
   company, because nothing else in the line does.

   Two files, and the difference matters:
     founded-ai.png            as supplied. Black lettering on a SOLID WHITE
                               rectangle, no transparency at all. Correct on a
                               light ground, a white box on this footer.
     founded-ai-reversed.png   what the footer uses. Same artwork with the
                               white ground removed and the neutral lettering
                               taken to paper ink. The pink, orange and yellow
                               squares are untouched. Unusable on light. */
.site-footer__credit {
  flex-basis: 100%;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
}

/* The lockup links to founded.ai. Block, so the focus ring hugs the logo. */
/* A partner's logo inside a news item. The artwork carries its own dark plate,
   so it is not given a background of its own and it sits unchanged in both
   themes. Capped by width rather than height because these arrive at whatever
   size the partner supplies, and never scaled up past their own pixels. */
.partner-logo { margin-block-start: var(--sp-4); }
.partner-logo a { display: inline-block; }
.partner-logo img {
  display: block;
  inline-size: auto;
  block-size: auto;
  max-inline-size: min(100%, 220px);
  border-radius: var(--r-xs);
}

.site-footer__founded-link { display: block; }

.site-footer__credit .site-footer__founded-logo {
  display: block;
  height: 1.5em;
  width: auto;
}

/* ==========================================================================
   STAT BLOCK — numbers are the campaign's rhetoric, so they are enormous.
   ========================================================================== */

.stat { display: block; }
.stat__value {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-3xl);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  font-variant-numeric: tabular-nums;
}
.stat__unit {
  display: block;
  margin-top: var(--sp-2);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.stat--nav .stat__value { font-size: var(--fs-2xl); }

/* ==========================================================================
   DATA STATES — loading, empty, error.

   Rendered by lib/fetch-json.js into any region it manages. These are the
   only three states a data-driven region can be in, they look the same
   everywhere, and they are announced because the region is a live region.
   A region that fails leaves the static content around it untouched.
   ========================================================================== */

.data-state {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  max-width: var(--measure);
  padding: var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
}
.data-state::before {
  flex: none;
  font-weight: var(--fw-black);
  font-family: var(--font-display);
}

.data-state--loading {
  background-color: var(--c-surface-3);
  color: var(--c-text-muted);
}
.data-state--loading::before { content: "\2026"; }

.data-state--empty {
  background-color: var(--c-surface-3);
  color: var(--c-text-muted);
  border: var(--bw-hair) dashed var(--c-border-strong);
}
.data-state--empty::before { content: "\2014"; }

.data-state--error {
  background-color: var(--c-error-bg);
  color: var(--c-error);
  border: var(--bw-hair) solid var(--c-error);
}
.data-state--error::before { content: "!"; }

/* While a region is loading, whatever it already contains stays put; it is
   dimmed so the reader can see something is happening without the content
   jumping. */
[data-state="loading"] > *:not(.data-state) { opacity: var(--o-muted); }

/* ==========================================================================
   DATA TABLE — sticky header, its own horizontal scroll container.
   Also the fallback for every chart, so it must stand on its own.
   ========================================================================== */

.data-table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
.data-table caption {
  text-align: left;
  padding-block: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.data-table :is(th, td) {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: var(--bw-hair) solid var(--c-border);
  text-align: left;
  vertical-align: top;
}
.data-table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background-color: var(--c-surface-3);
  border-bottom: var(--bw-thin) solid var(--c-border-strong);
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  white-space: nowrap;
}
.data-table tbody th { font-weight: var(--fw-bold); }
.data-table .is-numeric { text-align: right; }
.data-table tbody tr:hover { background-color: var(--c-hover-wash); }

/* ==========================================================================
   CHARTS
   Hand-authored SVG, generated from local JSON. No charting library, no CDN.
   ========================================================================== */

.chart { display: block; }
.chart__figure { margin: 0; position: relative; }

.chart__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: var(--lh-heading);
  margin-bottom: var(--sp-2);
}

.chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  list-style: none;
  padding: 0;
  margin-block: var(--sp-2) var(--sp-4);
  font-size: var(--fs-xs);
}
.chart__legend[hidden] { display: none; }
.chart__legenditem { display: flex; align-items: center; gap: var(--sp-2); }
.chart__swatch {
  border: var(--bw-hair) solid var(--c-border-strong);
  border-radius: var(--r-xs);
}

.chart__plot { position: relative; }

.chart__svg {
  display: block;
  inline-size: 100%;
  block-size: auto;
  overflow: visible;
}
.chart__svg:focus-visible {
  outline: var(--focus-width) solid var(--c-focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 8px var(--c-focus-halo);
  border-radius: var(--r-sm);
}
.chart__defs { position: absolute; inline-size: 0; block-size: 0; }

.chart__gridline { stroke: var(--c-chart-grid); stroke-width: 1; }
.chart__axisline { stroke: var(--c-chart-axis); stroke-width: 1.5; }
.chart__ticklabel {
  fill: var(--c-chart-label);
  font-family: var(--font-text);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.chart__barlabel {
  fill: var(--c-text);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: var(--fw-bold);
}

.chart__bar,
.chart__area {
  stroke: var(--c-paper);
  stroke-width: 1;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.chart__area { fill-opacity: 0.9; }

/* Hovering or focusing one mark dims the others rather than recolouring
   them, so nothing depends on colour alone. */
.chart__marks:hover .chart__bar:not(:hover),
.chart__marks:hover .chart__area:not(:hover) { opacity: var(--o-dim); }
.chart__marks .is-active { opacity: 1 !important; }
.chart__marks:has(.is-active) .chart__bar:not(.is-active),
.chart__marks:has(.is-active) .chart__area:not(.is-active) { opacity: var(--o-dim); }
.chart__bar.is-active,
.chart__area.is-active { stroke: var(--c-ink); stroke-width: 2.5; }

.chart__tooltip {
  position: absolute;
  z-index: var(--z-raised);
  max-inline-size: 20rem;
  padding: var(--sp-3);
  background-color: var(--c-surface-invert);
  color: var(--c-text-invert);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-3);
  font-size: var(--fs-xs);
  pointer-events: none;
  display: grid;
  grid-template-columns: auto auto;
  gap: var(--sp-1) var(--sp-3);
}
.chart__tooltip[hidden] { display: none; }
.chart__tiptitle {
  grid-column: 1 / -1;
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  color: var(--c-floodlight);
}
.chart__tipkey { color: color-mix(in srgb, var(--c-text-invert) 70%, transparent); }
.chart__tipval { text-align: right; font-variant-numeric: tabular-nums; }

.chart__controls { margin-block: var(--sp-4) var(--sp-2); }

/* The table is always in the DOM: reachable by screen readers and by
   keyboard, revealed for everyone by the toggle.

   The hiding is applied to the WRAPPER, never to the table. A table will not
   shrink below its min-content width, so hiding the table itself leaves a
   box several hundred pixels wide positioned against the initial containing
   block, which pushes the whole page sideways at 320px. The wrapper is a
   div, and a div does as it is told. */
.chart__table:not(.is-open) {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.chart__table.is-open {
  position: static;
  max-block-size: 32rem;
  overflow: auto;
  margin-block-start: var(--sp-3);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}

/* ---- Small multiples ----------------------------------------------------- */

.chart__multiples {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--sp-4);
}
.chart__multiple {
  padding: var(--sp-3);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
  background-color: var(--c-surface-2);
}
.chart__multiple-title {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  margin-bottom: var(--sp-2);
}
.chart__multiples::after {
  content: "All panels share one scale: " attr(data-shared-scale);
  grid-column: 1 / -1;
  font-size: var(--fs-2xs);
  color: var(--c-text-muted);
}

/* ==========================================================================
   CONFIDENCE MARKER
   Section 8: anything that is not `confirmed` must be visibly marked.
   Never colour alone — each level carries its own word and its own glyph.
   ========================================================================== */

.confidence {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.1em 0.5em;
  border-radius: var(--r-pill);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  white-space: nowrap;
}
.confidence::before { font-weight: var(--fw-black); }

.confidence--estimate {
  background-color: var(--c-info-bg);
  color: var(--c-info);
  border: var(--bw-hair) solid var(--c-info);
}
.confidence--estimate::before { content: "\2248"; }

.confidence--confirmed {
  background-color: var(--c-success-bg);
  color: var(--c-success);
  border: var(--bw-hair) solid var(--c-success);
}
.confidence--confirmed::before { content: "\2713"; }

/* ---- THEME TOGGLE -------------------------------------------------------- */

.theme-toggle {
  display: inline-flex;
  gap: var(--sp-1);
  padding: var(--sp-1);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-pill);
}
.theme-toggle .btn { border-radius: var(--r-pill); }

/* ==========================================================================
   THE FUNDING FLOW DIAGRAM
   Hand-built SVG Sankey. See charts/flow-diagram.js.
   ========================================================================== */

.flow { display: block; }
.flow__figure { margin: 0; position: relative; }

.flow__controls { margin-block-end: var(--sp-4); }
.flow__seasons { display: flex; gap: var(--sp-2); }
.flow__seasonnote {
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  max-inline-size: var(--measure);
}
.flow__seasonnote strong {
  font-family: var(--font-display);
  color: var(--c-text);
}

/* The diagram scrolls inside its own container if it must. The page never
   scrolls sideways because of it. */
.flow__scroller {
  position: relative;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
  padding-block: var(--sp-3);
}

.flow__svg { display: block; }
.flow__svg:focus-visible { outline: none; }

/* ---- ribbons -------------------------------------------------------------- */

.flow__hit {
  stroke: transparent;
  pointer-events: stroke;
}

.flow__ribbon {
  stroke: var(--c-pitch);
  stroke-opacity: 0.55;
  pointer-events: none;
  transition: stroke-opacity var(--dur-fast) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}

/* Hovering or focusing one ribbon dims every other to 20%. */
.flow__svg.is-highlighting .flow__link:not(.is-active) .flow__ribbon,
.flow__svg.is-highlighting .flow__node:not(.is-active) { opacity: var(--o-dim); }

.flow__link.is-active .flow__ribbon {
  stroke-opacity: 0.95;
  stroke: var(--c-floodlight);
}
.flow__svg.is-pinned .flow__link.is-active .flow__ribbon {
  stroke: var(--c-floodlight);
}

.flow__link:focus { outline: none; }
.flow__link:focus-visible .flow__ribbon {
  stroke: var(--c-floodlight);
  stroke-opacity: 1;
}
.flow__link:focus-visible .flow__hit {
  stroke: var(--c-focus);
  stroke-opacity: 0.9;
  stroke-dasharray: 3 3;
}

/* ---- nodes ---------------------------------------------------------------- */

.flow__node {
  fill: var(--c-ink);
  transition: opacity var(--dur-fast) var(--ease-out);
}
.flow__node.is-active { fill: var(--c-alarm); }
.flow__node:focus { outline: none; }
.flow__node:focus-visible {
  stroke: var(--c-focus);
  stroke-width: 3;
  paint-order: stroke;
}

.flow__label {
  font-family: var(--font-text);
  font-size: 12px;
  fill: var(--c-text);
}
.flow__label-name { font-weight: var(--fw-bold); }
.flow__label-value {
  font-family: var(--font-display);
  font-size: 13px;
  fill: var(--c-text-muted);
  font-variant-numeric: tabular-nums;
}

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

.flow__tooltip {
  position: absolute;
  z-index: var(--z-raised);
  inline-size: min(22rem, 82vw);
  padding: var(--sp-4);
  background-color: var(--c-surface-invert);
  color: var(--c-text-invert);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  font-size: var(--fs-xs);
  pointer-events: none;
}
.flow__tooltip[hidden] { display: none; }
.flow__tiptitle {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  color: var(--c-floodlight);
  margin-block-end: var(--sp-2);
}
.flow__tiprows {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-1) var(--sp-3);
  margin: 0;
}
.flow__tiprows dt { color: color-mix(in srgb, var(--c-text-invert) 68%, transparent); }
.flow__tiprows dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.flow__tipnote,
.flow__tipsource {
  margin-block-start: var(--sp-3);
  padding-block-start: var(--sp-2);
  border-block-start: var(--bw-hair) solid color-mix(in srgb, var(--c-text-invert) 22%, transparent);
  color: color-mix(in srgb, var(--c-text-invert) 82%, transparent);
}
.flow__tipsource { font-style: italic; }
.flow__tooltip .confidence { margin-block-end: var(--sp-2); }

.flow__caption {
  margin-block-start: var(--sp-3);
  max-inline-size: var(--measure);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}

/* ---- the table fallback ---------------------------------------------------
   Always in the DOM. Hidden on the wrapper, never on the table itself. */

.flow__table:not(.is-open) {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.flow__table.is-open {
  position: static;
  max-block-size: 34rem;
  overflow: auto;
  margin-block-start: var(--sp-4);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}

/* ==========================================================================
   SECTION HEADER — kicker, title, lede. Used at the top of every section.
   ========================================================================== */

.section-head { margin-block-end: var(--sp-6); }
.section-head__kicker {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  font-weight: var(--fw-black);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-pitch);
  margin-block-end: var(--sp-2);
}
.section--invert .section-head__kicker { color: var(--c-floodlight); }
/* Pitch green is dark in light mode and light in dark mode, so an accent on
   it cannot be a fixed colour. See --c-accent-on-brand in tokens.css. */
.section--brand .section-head__kicker { color: var(--c-accent-on-brand); }
.section-head__title {
  font-size: var(--fs-3xl);
  max-inline-size: 18ch;
  text-wrap: balance;
}
.section-head__lede { margin-block-start: var(--sp-4); }

/* Three columns of running prose, per section 6.1 item 5. */
.columns-prose h3 {
  font-size: var(--fs-lg);
  margin-block-end: var(--sp-3);
  padding-block-start: var(--sp-3);
  border-block-start: var(--bw-thick) solid var(--c-pitch);
}
.columns-prose p { font-size: var(--fs-base); }

/* ==========================================================================
   REVEAL — decoration only. The finished state is the default; the offset is
   applied only when JavaScript is present, and removed as the element scrolls
   into view. No JavaScript, or reduced motion, means no offset ever.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .js [data-reveal] {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity var(--dur-slow) var(--ease-out),
                transform var(--dur-slow) var(--ease-out);
  }
  .js [data-reveal].is-revealed { opacity: 1; transform: none; }
}

/* ==========================================================================
   ASK CARD
   ========================================================================== */

.ask-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--sp-4);
}
.ask-card { display: flex; }
.ask-card__link {
  display: grid;
  gap: var(--sp-2);
  align-content: start;
  inline-size: 100%;
  padding: var(--sp-5);
  background-color: var(--c-surface);
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-md);
  color: var(--c-text);
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.ask-card__link:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: var(--c-pitch);
  color: var(--c-text);
}
.ask-card__icon { color: var(--c-pitch); }
.ask-card__number {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
}
.ask-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
}
.ask-card__summary { font-size: var(--fs-sm); color: var(--c-text-muted); }

/* ==========================================================================
   TICKET STUB — the club story card.
   The serrated edge is a repeating radial gradient used as a mask, so it
   punches real holes rather than drawing circles in a fixed background
   colour: the card works on any surface and in either theme.
   ========================================================================== */

.ticket { display: flex; }
.ticket__link {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  inline-size: 100%;
  background-color: var(--c-surface);
  border-radius: var(--r-sm);
  color: var(--c-text);
  text-decoration: none;
  box-shadow: var(--shadow-1);
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.ticket__link:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-3);
  color: var(--c-text);
}

.ticket__stub {
  display: grid;
  align-content: center;
  gap: var(--sp-1);
  padding: var(--sp-4) var(--sp-3);
  background-color: var(--c-pitch);
  color: var(--c-text-on-brand);
  text-align: center;
}
.ticket__step {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  line-height: var(--lh-tight);
}
.ticket__region {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  opacity: 0.9;
}

.ticket__body {
  display: grid;
  align-content: start;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-5);
  position: relative;
}
/* The perforation: holes punched down the join between stub and body. */
.ticket__body::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: -5px;
  inline-size: 10px;
  background-image: radial-gradient(circle at 50% 50%, var(--c-surface-sunk) 0 4px, transparent 4px);
  background-size: 10px 14px;
  background-repeat: repeat-y;
}
.ticket__flag {
  justify-self: start;
  padding: 0.1em 0.5em;
  border: var(--bw-hair) solid var(--c-border-strong);
  border-radius: var(--r-pill);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.ticket__club {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
}
.ticket__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
}
.ticket__excerpt { font-size: var(--fs-sm); color: var(--c-text-muted); }

/* ==========================================================================
   THE LADDER — the recurring motif. Rungs widen as they descend.
   ========================================================================== */

.ladder { list-style: none; padding: 0; margin: 0; }
.ladder__rung + .ladder__rung { margin-block-start: var(--sp-1); }
.ladder__rung a {
  display: grid;
  grid-template-columns: minmax(2.5rem, calc(2rem + (var(--rung) * 1.5rem))) 1fr;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--c-text);
  text-decoration: none;
}
.ladder__rung a:hover { background-color: var(--c-hover-wash); color: var(--c-text); }
.ladder__bar {
  block-size: 0.75rem;
  background-color: var(--c-pitch);
  border-radius: var(--r-xs);
  opacity: calc(0.4 + (var(--rung) * 0.085));
}
.ladder__name {
  grid-column: 2;
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: var(--fw-black);
}
.ladder__meta {
  grid-column: 2;
  font-size: var(--fs-2xs);
  color: var(--c-text-muted);
}
.ladder__est {
  font-style: italic;
  border-block-end: var(--bw-hair) dotted currentColor;
  cursor: help;
}
.ladder-wrap {
  padding: var(--sp-4);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}

/* ==========================================================================
   ROUTE — a numbered call to action.
   ========================================================================== */

.route-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--sp-6);
}
.route { position: relative; padding-block-start: var(--sp-5); }
.route::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0 40%;
  block-size: var(--bw-slab);
  background-color: var(--c-accent-on-brand);
}
.route__number {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  color: var(--c-accent-on-brand);
  line-height: 1;
}
.route__title { font-size: var(--fs-lg); margin-block: var(--sp-2); }
.route__title a { text-decoration: none; }
.route__title a:hover { text-decoration: underline; }
.route p { font-size: var(--fs-sm); }

/* ==========================================================================
   CITATION CHIP
   A native <details>, so it expands on click with no JavaScript at all and
   prints open (see print.css).
   ========================================================================== */

.citation {
  display: inline-block;
  vertical-align: baseline;
  max-inline-size: 100%;
}
.citation__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.1em 0.6em;
  border: var(--bw-hair) solid var(--c-border-strong);
  border-radius: var(--r-pill);
  background-color: var(--c-surface-2);
  color: var(--c-text-muted);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  cursor: pointer;
  list-style: none;
}
.citation__chip::-webkit-details-marker { display: none; }
.citation__chip::after {
  content: "+";
  font-weight: var(--fw-black);
}
.citation[open] > .citation__chip::after { content: "\2212"; }
.citation__chip:hover {
  border-color: var(--c-pitch);
  color: var(--c-text);
}

.citation__body {
  margin-block-start: var(--sp-2);
  padding: var(--sp-4);
  max-inline-size: var(--measure);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-inline-start: var(--bw-slab) solid var(--c-pitch);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}
.citation__body > * + * { margin-block-start: var(--sp-2); }
.citation__meta { font-size: var(--fs-xs); color: var(--c-text-muted); }
.citation__kind {
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-size: var(--fs-2xs);
}
.citation__links { font-size: var(--fs-xs); }

/* ==========================================================================
   ARTICLE PAGE FURNITURE
   The template every deep page in The Case uses: a page head, a claim panel
   stating the argument in one sentence, evidence, a counter-argument panel,
   and a closing action block.
   ========================================================================== */

.page-head { margin-block-end: var(--sp-6); }
.page-head__kicker {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-pitch);
  margin-block-end: var(--sp-2);
}
.page-head h1 { max-inline-size: 20ch; }

/* ---- The claim ----------------------------------------------------------- */

.claim {
  margin-block: var(--sp-6) var(--sp-7);
  padding: var(--sp-5) var(--sp-6);
  background-color: var(--c-surface-3);
  border-inline-start: var(--bw-slab) solid var(--c-pitch);
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.claim__title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
  margin-block-end: var(--sp-2);
}
.claim__text {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  line-height: var(--lh-snug);
  max-inline-size: var(--measure-wide);
}
.claim__text em { font-style: italic; }

/* ---- The counter-argument ------------------------------------------------ */

.counter {
  margin-block: var(--sp-8);
  padding: var(--sp-6);
  background-color: var(--c-surface-2);
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-md);
}
.counter__title {
  font-size: var(--fs-xl);
  margin-block-end: var(--sp-4);
  padding-block-end: var(--sp-3);
  border-block-end: var(--bw-hair) solid var(--c-border);
}
.counter__title::before {
  content: "⚖";
  margin-inline-end: var(--sp-3);
  color: var(--c-text-muted);
}
.counter__body strong { color: var(--c-pitch); }

/* ---- The closing action block -------------------------------------------- */

.action-block {
  margin-block-start: var(--sp-8);
  padding: var(--sp-6);
  background-color: var(--c-surface-brand);
  color: var(--c-text-on-brand);
  border-radius: var(--r-md);
}

/* ---- DATA NOTICE ---------------------------------------------------------
   The standing caveat at the foot of the homepage. Same dark ground as the
   hero at the top of the page and as the footer below it, which is why it
   uses the surface token rather than a literal: in dark mode all three drop
   together and the panel does not end up lighter than the page it sits on. */

.data-notice {
  padding: var(--sp-6);
  border-radius: var(--r-md);
  background-color: var(--c-surface-invert);
  color: var(--c-text-invert);
}

.data-notice p { margin-block: 0 var(--sp-4); }
.data-notice p:last-child { margin-block-end: 0; }

/* The links have to clear contrast against the dark ground, so they take the
   same accent the footer links use rather than the body link colour. */
.data-notice a {
  color: var(--c-floodlight);
  text-underline-offset: 0.2em;
}

.data-notice__date {
  color: color-mix(in srgb, var(--c-text-invert) 78%, transparent);
}
.action-block__title { color: var(--c-text-on-brand); font-size: var(--fs-xl); }
.action-block > * + * { margin-block-start: var(--sp-4); }
.action-block .prose { color: var(--c-text-on-brand); }

/* ---- Link cards ---------------------------------------------------------- */

.link-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  gap: var(--sp-4);
  margin-block-start: var(--sp-5);
}
.link-card a {
  display: grid;
  gap: var(--sp-2);
  block-size: 100%;
  padding: var(--sp-5);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
  color: var(--c-text);
  text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.link-card a:hover {
  border-color: var(--c-pitch);
  transform: translateY(-2px);
  color: var(--c-text);
}
.link-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
}
.link-card__desc { font-size: var(--fs-sm); color: var(--c-text-muted); }

/* ---- Chart and flow hosts ------------------------------------------------- */

.chart-host,
.flow-host {
  margin-block: var(--sp-6);
  padding: var(--sp-5);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}

/* ==========================================================================
   TIMELINE
   ========================================================================== */

.timeline {
  list-style: none;
  padding: 0;
  margin-block: var(--sp-6);
  position: relative;
}
.timeline::before {
  content: "";
  position: absolute;
  inset-block: 0.6rem 2rem;
  inset-inline-start: 0.45rem;
  inline-size: var(--bw-thin);
  background-color: var(--c-border);
}
.timeline__item {
  position: relative;
  padding-inline-start: var(--sp-6);
  padding-block-end: var(--sp-6);
}
.timeline__item::before {
  content: "";
  position: absolute;
  inset-block-start: 0.4rem;
  inset-inline-start: 0;
  inline-size: 1rem;
  block-size: 1rem;
  border-radius: var(--r-pill);
  background-color: var(--c-surface);
  border: var(--bw-thick) solid var(--c-border-strong);
}
.timeline__item--now::before { background-color: var(--c-floodlight); border-color: var(--c-ink); }
.timeline__item--future::before { background-color: var(--c-surface); border-style: dashed; }
.timeline__date {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.timeline__body h3,
.timeline__body h4 { font-size: var(--fs-md); margin-block: var(--sp-1) var(--sp-2); }
.timeline__body p { font-size: var(--fs-sm); max-inline-size: var(--measure); }
.timeline__body > p + p { margin-block-start: var(--sp-2); }

/* ==========================================================================
   THE FULL ASK LIST
   ========================================================================== */

.ask-list { list-style: none; padding: 0; margin: 0; counter-reset: ask; }
.ask-full {
  padding-block: var(--sp-7);
  border-block-start: var(--bw-thick) solid var(--c-ink);
  scroll-margin-top: calc(var(--header-h) + var(--sp-5));
}
.ask-full__number {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-pitch);
}
.ask-full__title { font-size: var(--fs-2xl); margin-block: var(--sp-2) var(--sp-3); }
.ask-full__short {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  max-inline-size: var(--measure);
  margin-block-end: var(--sp-4);
}
.ask-full h3 {
  font-size: var(--fs-md);
  margin-block-start: var(--sp-5);
  color: var(--c-text-muted);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  font-size: var(--fs-xs);
}

/* ==========================================================================
   BUTTONS ON A BRAND OR INVERTED SURFACE

   .btn--outline and .btn--ghost take their foreground from --c-text, which is
   computed against the page ground. Drop one onto pitch green or onto the
   dark slab and the label lands at about 2.2:1. Rather than patching each
   place it happens, every surface that changes the ground is listed here once.

   The hero has its own version because it sits on photography rather than a
   flat colour.
   ========================================================================== */

/* `color` is declared alongside --btn-fg throughout this block. On its own,
   --btn-fg relies on these rules outranking .btn--outline / .btn--ghost, which
   set it from --c-text. The descendant selector does win on specificity, but a
   label that is unreadable when one rule loses is not worth the elegance —
   declaring the property directly makes the outcome independent of the
   cascade. All four surfaces are dark, so all four take plain white. */

:is(.section--brand, .action-block) :is(.btn--outline, .btn--ghost),
:is(.section--brand, .action-block) :is(.btn--outline, .btn--ghost):hover,
:is(.section--brand, .action-block) :is(.btn--outline, .btn--ghost):focus-visible {
  --btn-fg: var(--c-text-on-dark);
  --btn-bd: var(--c-text-on-dark);
  color: var(--c-text-on-dark);
}
:is(.section--brand, .action-block) .btn--ghost { --btn-bd: transparent; }
:is(.section--brand, .action-block) :is(.btn--outline, .btn--ghost):hover {
  --btn-bg: color-mix(in srgb, var(--c-text-on-dark) 16%, transparent);
}
:is(.section--brand, .action-block) .btn--outline:hover { --btn-bd: var(--c-text-on-dark); }

:is(.section--invert, .numberband) :is(.btn--outline, .btn--ghost),
:is(.section--invert, .numberband) :is(.btn--outline, .btn--ghost):hover,
:is(.section--invert, .numberband) :is(.btn--outline, .btn--ghost):focus-visible {
  --btn-fg: var(--c-text-on-dark);
  --btn-bd: var(--c-text-on-dark);
  color: var(--c-text-on-dark);
}
:is(.section--invert, .numberband) .btn--ghost { --btn-bd: transparent; }
:is(.section--invert, .numberband) :is(.btn--outline, .btn--ghost):hover {
  --btn-bg: color-mix(in srgb, var(--c-text-on-dark) 16%, transparent);
}

/* The accent button keeps its own amber ground everywhere, so it needs no
   variant — but on brand green it needs a border that separates it. */
:is(.section--brand, .action-block) .btn--accent {
  --btn-bd: var(--c-text-on-brand);
}

/* ==========================================================================
   CALLOUT — a panel that says something about the data itself.
   ========================================================================== */

.callout {
  margin-block: var(--sp-5);
  padding: var(--sp-5);
  border-radius: var(--r-md);
  border: var(--bw-thin) solid var(--c-border-strong);
  background-color: var(--c-surface-2);
}
.callout > * + * { margin-block-start: var(--sp-3); }
.callout h3 { font-size: var(--fs-md); }
.callout--gap { border-style: dashed; }
.callout--seed { border-inline-start: var(--bw-slab) solid var(--c-floodlight); }

/* ==========================================================================
   THE STEP EXPLORER  (pyramid/steps.html)

   Ships fully expanded. [data-enhanced] is set by pyramid-explorer.js, and
   only then does it behave as a disclosure set — so the collapsed state can
   never be what a reader without JavaScript is left with.
   ========================================================================== */

.explorer { list-style: none; padding: 0; margin-block: var(--sp-6); }

.explorer__rung {
  border-block-start: var(--bw-thin) solid var(--c-border);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.explorer__rung:last-child { border-block-end: var(--bw-thin) solid var(--c-border); }

.explorer__heading { font: inherit; margin: 0; }

.explorer__trigger {
  display: grid;
  grid-template-columns: minmax(3rem, calc(2.5rem + (var(--rung) * 1.8rem))) 1fr auto;
  align-items: center;
  gap: var(--sp-4);
  inline-size: 100%;
  padding: var(--sp-4) var(--sp-2);
  text-align: left;
  color: var(--c-text);
}
.explorer__trigger:hover { background-color: var(--c-hover-wash); }

.explorer__bar {
  block-size: 1.1rem;
  background-color: var(--c-pitch);
  border-radius: var(--r-xs);
  opacity: calc(0.38 + (var(--rung) * 0.085));
}
.explorer__name {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
}
.explorer__summary {
  display: block;
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  max-inline-size: 52ch;
}
.explorer__count {
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  text-align: right;
  white-space: nowrap;
}
.explorer__count b {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  color: var(--c-text);
}

/* The chevron only appears once the module has made these into buttons that
   actually do something. */
[data-enhanced] .explorer__trigger { position: relative; }
[data-enhanced] .explorer__name::after {
  content: "";
  display: inline-block;
  inline-size: 0.55em;
  block-size: 0.55em;
  margin-inline-start: var(--sp-3);
  border-inline-end: var(--bw-thick) solid currentColor;
  border-block-end: var(--bw-thick) solid currentColor;
  transform: rotate(45deg) translate(-0.1em, -0.1em);
  transition: transform var(--dur-fast) var(--ease-out);
  opacity: 0.6;
}
[data-enhanced] .explorer__rung.is-open .explorer__name::after {
  transform: rotate(-135deg) translate(-0.16em, -0.16em);
}
[data-enhanced] .explorer__rung.is-open { background-color: var(--c-surface-2); }

.explorer__panel { padding-inline: var(--sp-2); }
.explorer__panel[hidden] { display: none; }

.explorer__detail {
  max-inline-size: var(--measure-wide);
  padding-block: var(--sp-2) var(--sp-6);
}
.explorer__detail > * + * { margin-block-start: var(--sp-4); }
.explorer__detail h3 {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
}
.explorer__detail p { font-size: var(--fs-base); max-inline-size: var(--measure); }
.explorer__leagues,
.explorer__clubs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--sp-1) var(--sp-5);
  font-size: var(--fs-sm);
  padding-inline-start: var(--sp-5);
}
.explorer__note {
  font-size: var(--fs-xs) !important;
  color: var(--c-text-muted);
}
.explorer__needs {
  padding: var(--sp-4);
  border-inline-start: var(--bw-slab) solid var(--c-floodlight);
  background-color: var(--c-surface-3);
  font-weight: var(--fw-bold);
}

/* ---- Facts, with honest gaps --------------------------------------------- */

.factlist {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
  gap: var(--sp-4);
  margin: 0;
}
.factlist dt {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.factlist dd {
  margin: var(--sp-1) 0 0;
  font-family: var(--font-display);
  font-size: var(--fs-md);
}
.factlist dd .confidence { font-family: var(--font-text); }
.factlist__missing {
  font-size: var(--fs-xs) !important;
  color: var(--c-text-muted);
  padding: var(--sp-3);
  border: var(--bw-hair) dashed var(--c-border-strong);
  border-radius: var(--r-sm);
}

/* ---- The modelled funding index ------------------------------------------ */

.indexbar { max-inline-size: var(--measure); }
.indexbar__track {
  block-size: var(--sp-5);
  background-color: var(--c-surface-sunk);
  border: var(--bw-hair) solid var(--c-border-strong);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.indexbar__fill {
  block-size: 100%;
  inline-size: var(--pct);
  background-color: var(--c-pitch);
  background-image: repeating-linear-gradient(
    135deg, transparent 0 6px,
    color-mix(in srgb, var(--c-paper) 24%, transparent) 6px 12px
  );
}
.indexbar__label { font-size: var(--fs-sm) !important; margin-block-start: var(--sp-2); }

/* ==========================================================================
   THE CLUB FINDER  (pyramid/club-finder.html)
   ========================================================================== */

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--sp-4);
  margin-block: var(--sp-6) var(--sp-4);
  padding: var(--sp-4);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}
/* min-inline-size: 0 matters more than it looks. A flex item defaults to
   min-width: auto, and a <select> reports the width of its longest option as
   its minimum, so at 320px a filter with a long option name pushed itself off
   the side of the screen. Letting the field shrink, and holding the control to
   the width of the field, keeps every filter reachable on the narrowest phone. */
.filters__field {
  display: grid;
  gap: var(--sp-1);
  flex: 1 1 12rem;
  min-inline-size: 0;
}
.filters__field label {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.filters :is(select, input) {
  padding: var(--sp-2) var(--sp-3);
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-sm);
  background-color: var(--c-surface);
  color: var(--c-text);
  font-size: var(--fs-sm);
  min-block-size: 2.75rem;
  inline-size: 100%;
  min-inline-size: 0;
  max-inline-size: 100%;
}
.filters__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* The submit button is the no-JavaScript path. Once the module takes over,
   filtering happens as you type and the button is redundant. */
[data-enhanced] .filters__submit { display: none; }

.finder__count {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
  margin-block-end: var(--sp-4);
}
.finder__empty {
  padding: var(--sp-5);
  border: var(--bw-thin) dashed var(--c-border-strong);
  border-radius: var(--r-md);
  color: var(--c-text-muted);
}

.finder {
  display: grid;
  gap: var(--sp-6);
  align-items: start;
}
@media (min-width: 62rem) {
  .finder { grid-template-columns: minmax(0, 1fr) 24rem; }
  .clubmap { position: sticky; top: calc(var(--header-h) + var(--sp-4)); }
}

.clublist { display: grid; gap: var(--sp-2); }
.clubrow {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-sm);
}
.clubrow[hidden] { display: none; }
.clubrow.is-selected { border-color: var(--c-pitch); background-color: var(--c-selected); }
.clubrow__step {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  text-align: center;
  padding: var(--sp-1) var(--sp-2);
  background-color: var(--c-pitch);
  color: var(--c-text-on-brand);
  border-radius: var(--r-xs);
}
.clubrow__body { display: grid; gap: 2px; }
.clubrow__name { font-family: var(--font-display); font-size: var(--fs-base); font-weight: var(--fw-black); }
.clubrow__place { font-size: var(--fs-xs); color: var(--c-text-muted); }
.clubrow__story { font-size: var(--fs-xs); justify-self: start; }

/* ---- The schematic map --------------------------------------------------- */

.clubmap {
  padding: var(--sp-4);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}
.clubmap__title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
  margin-block-end: var(--sp-3);
}
.clubmap__svg { inline-size: 100%; block-size: auto; }
.clubmap__coast {
  fill: color-mix(in srgb, var(--c-pitch) 12%, var(--c-surface));
  stroke: var(--c-border-strong);
  stroke-width: 1.5;
  stroke-linejoin: round;
}
.clubmap__region {
  font-family: var(--font-text);
  font-size: 11px;
  fill: var(--c-text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.clubmap__region.is-filtered { opacity: 0.25; }
.clubmap__point {
  fill: var(--c-pitch);
  stroke: var(--c-surface);
  stroke-width: 1.5;
  cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-out),
              r var(--dur-fast) var(--ease-out);
}
.clubmap__point.is-filtered { opacity: 0.12; pointer-events: none; }
.clubmap__point.is-hover { fill: var(--c-alarm); r: 9; }
.clubmap__note {
  margin-block-start: var(--sp-3);
  font-size: var(--fs-2xs);
  color: var(--c-text-muted);
}

/* ==========================================================================
   FORMS
   Every message is tied to its field with aria-describedby and given
   role="alert", so a screen reader hears the problem next to the thing that
   caused it rather than in a summary at the top.
   ========================================================================== */

.field { margin-block-end: var(--sp-5); max-inline-size: var(--measure); }
.field > label {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  margin-block-end: var(--sp-2);
}
.field__req,
.field__opt {
  font-family: var(--font-text);
  font-weight: var(--fw-regular);
  font-size: var(--fs-2xs);
  text-transform: none;
  letter-spacing: 0;
  color: var(--c-text-muted);
}
.field__req { color: var(--c-error); }

.field :is(input[type="text"], input[type="email"], input[type="search"], textarea) {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding: var(--sp-3);
  background-color: var(--c-surface);
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-sm);
  color: var(--c-text);
  font-size: var(--fs-base);
}
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--c-error);
  background-color: var(--c-error-bg);
}

.field__help {
  margin-block-start: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.field__error {
  margin-block-start: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background-color: var(--c-error-bg);
  border-inline-start: var(--bw-thick) solid var(--c-error);
  border-radius: var(--r-xs);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  color: var(--c-error);
}
.field__error[hidden] { display: none; }

.field--check {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-2) var(--sp-3);
  align-items: start;
  padding: var(--sp-4);
  background-color: var(--c-surface-3);
  border-radius: var(--r-md);
}
.field--check input { inline-size: 1.4rem; block-size: 1.4rem; margin-block-start: 0.1rem; }
.field--check > label {
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--font-text);
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  margin: 0;
}
.field--check :is(.field__help, .field__error) { grid-column: 1 / -1; }

/* The honeypot: away from the screen, out of the tab order, hidden from
   assistive technology, and dropped before submission. */
.field--honey {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.form-status {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  max-inline-size: var(--measure);
}
.form-status[hidden] { display: none; }
.form-status--working { background-color: var(--c-surface-3); color: var(--c-text-muted); }
.form-status--ok { background-color: var(--c-success-bg); color: var(--c-success); border: var(--bw-hair) solid var(--c-success); }
.form-status--error { background-color: var(--c-error-bg); color: var(--c-error); border: var(--bw-hair) solid var(--c-error); }

.form-success {
  padding: var(--sp-6);
  background-color: var(--c-success-bg);
  border: var(--bw-thin) solid var(--c-success);
  border-radius: var(--r-md);
  margin-block: var(--sp-6);
}
.form-success[hidden] { display: none; }
.form-success:focus { outline: none; }
.form-success h2 { color: var(--c-success); }
.form-success > * + * { margin-block-start: var(--sp-4); }

/* ==========================================================================
   MILESTONE GRAPHIC
   ========================================================================== */

.milestone {
  margin-block: var(--sp-6);
  padding: var(--sp-5);
  background-color: var(--c-surface-2);
  border: var(--bw-thin) solid var(--c-border-strong);
  border-radius: var(--r-md);
}
.milestone[hidden] { display: none; }
.milestone > * + * { margin-block-start: var(--sp-4); }
.milestone__title { font-size: var(--fs-lg); }
.milestone__canvas {
  inline-size: 100%;
  block-size: auto;
  border-radius: var(--r-sm);
  border: var(--bw-hair) solid var(--c-border);
}

/* ==========================================================================
   SHARE ROW — no third-party widgets, so this is just buttons.
   ========================================================================== */

.share-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-block: var(--sp-7);
  padding: var(--sp-4);
  border-block: var(--bw-thin) solid var(--c-border);
}
.share-row__title {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  margin: 0 var(--sp-3) 0 0;
}

/* ==========================================================================
   MP LOOKUP AND LETTER COMPOSER
   ========================================================================== */

.callout--privacy {
  border-inline-start: var(--bw-slab) solid var(--c-pitch);
  border-style: solid;
}
.callout--privacy h2 { font-size: var(--fs-md); }

.lookup-result {
  margin-block: var(--sp-4);
  padding: var(--sp-4);
  border-radius: var(--r-md);
  max-inline-size: var(--measure);
  font-size: var(--fs-sm);
}
.lookup-result[hidden] { display: none; }
.lookup-result > * + * { margin-block-start: var(--sp-3); }
.lookup-result--working { background-color: var(--c-surface-3); color: var(--c-text-muted); }
.lookup-result--ok { background-color: var(--c-success-bg); border: var(--bw-hair) solid var(--c-success); }
.lookup-result--fallback,
.lookup-result--error { background-color: var(--c-warn-bg); border: var(--bw-hair) solid var(--c-warn); color: var(--c-warn); }
.lookup-result--fallback a { color: inherit; }

.letter {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  min-block-size: 32rem;
}
.field:has(.letter) { max-inline-size: none; }

/* ==========================================================================
   DOWNLOADS GRID — ticket stubs for files.
   ========================================================================== */

.downloads {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: var(--sp-4);
  margin-block: var(--sp-6);
}
.download { display: flex; }
.download__link {
  display: grid;
  grid-template-columns: 7rem 1fr;
  inline-size: 100%;
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-sm);
  color: var(--c-text);
  text-decoration: none;
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.download__link:hover {
  transform: translateY(-3px);
  border-color: var(--c-pitch);
  color: var(--c-text);
}
.download__preview {
  display: grid;
  place-items: center;
  background-color: var(--c-surface-sunk);
  padding: var(--sp-2);
}
.download__preview img { inline-size: 100%; block-size: auto; border-radius: var(--r-xs); }
/* For artwork meant for a dark ground. The reversed lockup's lettering is
   paper, which on the sunk grey of an ordinary preview reads at 1.5:1 and so
   shows as nothing at all. */
.download__preview--dark { background-color: var(--c-surface-invert); }
.download__preview--doc {
  background-color: var(--c-pitch);
  color: var(--c-text-on-brand);
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  letter-spacing: var(--ls-caps);
}
.download__body {
  display: grid;
  align-content: start;
  gap: var(--sp-2);
  padding: var(--sp-4);
  /* The perforation between the stub and the body. */
  border-inline-start: var(--bw-hair) dashed var(--c-border-strong);
}
.download__title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: var(--fw-black);
  line-height: var(--lh-heading);
}
.download__desc { font-size: var(--fs-sm); color: var(--c-text-muted); }
.download__meta {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-faint);
}

/* The routes on a paper ground rather than the brand green. */
.route--light::before { background-color: var(--c-pitch); }
.route--light .route__number { color: var(--c-pitch); }

/* ==========================================================================
   SOURCES
   ========================================================================== */

.sources { counter-reset: src; margin-block: var(--sp-5) var(--sp-7); }
.source {
  counter-increment: src;
  position: relative;
  padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-8);
  border-block-end: var(--bw-hair) solid var(--c-border);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.source::before {
  content: counter(src);
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: var(--sp-4);
  inline-size: var(--sp-6);
  text-align: right;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  color: var(--c-text-faint);
}
.source:target { background-color: var(--c-selected); border-radius: var(--r-sm); }
.source > * + * { margin-block-start: var(--sp-2); }
.source__title { font-family: var(--font-display); font-size: var(--fs-md); }
.source__title cite { font-style: normal; }
.source__meta { font-size: var(--fs-xs); color: var(--c-text-muted); }
.source__links { font-size: var(--fs-xs); overflow-wrap: anywhere; }
.source__access { font-size: var(--fs-xs); color: var(--c-text-muted); }

/* ==========================================================================
   GLOSSARY
   ========================================================================== */

.glossary__index {
  margin-block: var(--sp-5);
  padding: var(--sp-4);
  background-color: var(--c-surface-3);
  border-radius: var(--r-md);
}
.glossary__jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin-block-start: var(--sp-3);
  font-size: var(--fs-sm);
}
.glossary { margin: 0; }
.glossary__entry {
  padding-block: var(--sp-5);
  border-block-start: var(--bw-hair) solid var(--c-border);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.glossary__entry:target { background-color: var(--c-selected); border-radius: var(--r-sm); }
.glossary__entry dt {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: var(--fw-black);
  margin-block-end: var(--sp-2);
}
.glossary__entry dd { margin: 0; max-inline-size: var(--measure); }
.glossary__entry dd > * + * { margin-block-start: var(--sp-2); }
.glossary__see,
.glossary__source { font-size: var(--fs-xs); color: var(--c-text-muted); }

/* ==========================================================================
   NEWS
   ========================================================================== */

.newslist { margin-block: var(--sp-6); }
.newsitem {
  padding-block: var(--sp-6);
  border-block-start: var(--bw-thick) solid var(--c-ink);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.newsitem:target { background-color: var(--c-selected); }
.newsitem__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--c-text-muted);
}
.newsitem__kind {
  padding: 0.05em 0.5em;
  border: var(--bw-hair) solid var(--c-border-strong);
  border-radius: var(--r-pill);
}
.newsitem[data-kind="press-release"] .newsitem__kind {
  background-color: var(--c-floodlight);
  color: var(--c-text-on-accent);
  border-color: var(--c-floodlight);
}
.newsitem__title { font-size: var(--fs-xl); margin-block: var(--sp-2); }
.newsitem__standfirst {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  max-inline-size: var(--measure);
  margin-block-end: var(--sp-4);
}
.pagination { margin-block: var(--sp-5); font-size: var(--fs-sm); color: var(--c-text-muted); }

/* ==========================================================================
   STORIES
   ========================================================================== */

.example-banner {
  padding: var(--sp-4);
  background-color: var(--c-warn-bg);
  border: var(--bw-thin) solid var(--c-warn);
  border-radius: var(--r-md);
  color: var(--c-warn);
  font-size: var(--fs-sm);
  max-inline-size: var(--measure-wide);
  margin-block-end: var(--sp-6);
}
.example-banner a { color: inherit; }

.story { max-inline-size: var(--measure); }
.story__standfirst {
  font-size: var(--fs-md);
  color: var(--c-text-muted);
  max-inline-size: var(--measure);
  margin-block-start: var(--sp-3);
}
.story__figure {
  margin-block-end: var(--sp-5);
  border-radius: var(--r-md);
}
.story__figure figcaption {
  position: relative;
  z-index: 2;
  padding: var(--sp-2) var(--sp-3);
  background-color: var(--c-surface-3);
  font-size: var(--fs-2xs);
  mix-blend-mode: normal;
}
.story h2 { font-size: var(--fs-xl); }

.pullquote {
  margin-block: var(--sp-6);
  padding: var(--sp-5);
  border-inline-start: var(--bw-slab) solid var(--c-floodlight);
  background-color: var(--c-surface-3);
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.pullquote p {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
}
.pullquote footer {
  margin-block-start: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}

.factsheet {
  padding: var(--sp-5);
  background-color: var(--c-surface-2);
  border: var(--bw-hair) solid var(--c-border);
  border-radius: var(--r-md);
}
.factsheet__title {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-kicker);
  color: var(--c-text-muted);
  margin-block: var(--sp-5) var(--sp-3);
}
.factsheet__title:first-child { margin-block-start: 0; }
.factsheet__list { margin: 0; }
.factsheet__list > div {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  padding-block: var(--sp-2);
  border-block-end: var(--bw-hair) dotted var(--c-border);
}
.factsheet__list dt { font-size: var(--fs-xs); color: var(--c-text-muted); }
.factsheet__list dd { margin: 0; font-family: var(--font-display); font-size: var(--fs-base); }
.factsheet__list dd.is-example {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--c-warn);
  border: var(--bw-hair) dashed var(--c-warn);
  border-radius: var(--r-xs);
  padding: 0 var(--sp-2);
}
.factsheet__note {
  margin-block-start: var(--sp-3);
  font-size: var(--fs-2xs);
  color: var(--c-text-muted);
}

.story-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: var(--sp-5);
  margin-block: var(--sp-6);
}

/* A plain definition value, where the term is a chip rather than a word. */
.u-plain { font-family: var(--font-text) !important; font-size: var(--fs-sm) !important; }

/* ==========================================================================
   FAQ — native disclosure, so it works with no JavaScript.
   ========================================================================== */

.faq { margin-block: var(--sp-6); }
.faq__item {
  border-block-start: var(--bw-hair) solid var(--c-border);
  scroll-margin-top: calc(var(--header-h) + var(--sp-4));
}
.faq__item:last-child { border-block-end: var(--bw-hair) solid var(--c-border); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-2);
  cursor: pointer;
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: var(--fw-black);
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: "+";
  flex: none;
  font-size: var(--fs-lg);
  color: var(--c-pitch);
}
.faq__item[open] .faq__q::after { content: "\2212"; }
.faq__q:hover { background-color: var(--c-hover-wash); }
.faq__a {
  padding: 0 var(--sp-2) var(--sp-5);
  max-inline-size: var(--measure);
  font-size: var(--fs-base);
}

/* ==========================================================================
   404
   ========================================================================== */

.notfound { text-align: left; }
.notfound__code {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  line-height: 1;
  color: var(--c-floodlight);
  -webkit-text-stroke: 2px var(--c-ink);
}
.notfound h1 { margin-block: var(--sp-3) var(--sp-4); }

/* ==========================================================================
   DATA EXPLORER
   ========================================================================== */

.explorer-note { margin-block: var(--sp-4); font-size: var(--fs-sm); }
.explorer-note p + p { margin-block-start: var(--sp-2); }
