@charset "utf-8";
/* ==========================================================================
   METUPUK design system
   Palette taken from the charity's own brand assets: the MET UP UK ribbon mark
   (pink fading to black), the "Darker Side of Pink" exhibition site
   (#440729 / #b52b65 / #e7b938) and the "Who Really Cares?" campaign artwork.
   ========================================================================== */

/* --- Tokens: light is the base, dark overrides only the colour roles ------ */
:root {
  /* Brand ramp — plum darkening out of pink, the logo's central idea. */
  --plum-950: #1c0310;
  --plum-900: #2b0519;
  --plum-800: #440729;
  --plum-700: #6b1140;
  --magenta-600: #b52b65;
  --magenta-500: #d2246f;
  --pink-400: #ec3f8e;
  --pink-300: #ff6fb5;
  --pink-100: #ffdcec;
  --pink-50: #fdf2f7;

  --gold-500: #e7b938;
  --gold-600: #c99a17;
  --gold-100: #fbf0d0;

  --slate-700: #44595e;
  --slate-500: #6c8086;

  --white: #ffffff;
  --paper: #fbf8f9;
  --bg-rgb: 255 255 255;   /* page colour as channels, for fades */
  --grey-100: #f1ecee;
  --grey-200: #e2d9dd;
  --grey-300: #c9bcc2;
  --grey-500: #7a6a71; /* 5.09:1 on white — passes AA at small sizes */
  --grey-700: #574a50;
  --ink: #241318;

  /* Semantic roles */
  --bg: var(--white);
  --bg-sunken: var(--paper);
  --bg-raised: var(--white);
  --bg-inverse: var(--plum-800);
  --surface-tint: var(--pink-50);
  --border: var(--grey-200);
  --border-strong: var(--grey-300);
  /* The boundary of a control the user has to find and click. --border is
     1.36:1 and --border-strong 2.02:1 against the page: fine for a divider,
     under the 3:1 WCAG 1.4.11 asks for wherever a border is the only thing
     defining an input. Measured at 3.30:1. */
  --border-control: #948b92;
  --text: var(--ink);
  --text-muted: var(--grey-700);
  --text-faint: var(--grey-500);
  --text-inverse: var(--white);
  --text-inverse-muted: #e6cdda;
  --link: var(--magenta-600);
  --link-hover: var(--plum-700);
  --accent: var(--magenta-600);
  --accent-contrast: var(--white);
  --focus: var(--plum-700);
  --shadow-sm: 0 1px 2px rgb(36 19 24 / 0.06), 0 1px 3px rgb(36 19 24 / 0.08);
  --shadow-md: 0 4px 12px rgb(36 19 24 / 0.08), 0 2px 4px rgb(36 19 24 / 0.06);
  --shadow-lg: 0 18px 40px rgb(36 19 24 / 0.14);

  /* Type */
  --font-display: "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* Slightly larger base than typical: much of this audience is reading while
     unwell, and the content is long-form. */
  --step--1: clamp(0.875rem, 0.85rem + 0.1vw, 0.94rem);
  --step-0: clamp(1.0625rem, 1.02rem + 0.22vw, 1.15rem);
  --step-1: clamp(1.25rem, 1.17rem + 0.38vw, 1.45rem);
  --step-2: clamp(1.5rem, 1.36rem + 0.66vw, 1.9rem);
  --step-3: clamp(1.85rem, 1.6rem + 1.15vw, 2.5rem);
  --step-4: clamp(2.2rem, 1.78rem + 2vw, 3.4rem);
  --step-5: clamp(2.3rem, 1.75rem + 2.3vw, 3.6rem);

  /* Space + shape. The upper end of the scale is generous on purpose:
     the old site's problem was density, not lack of content. */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2.25rem;
  --sp-7: 3.5rem;
  --sp-8: clamp(4rem, 7vw, 6rem);
  --sp-9: clamp(5.5rem, 10vw, 9rem);
  --radius: 10px;
  --radius-lg: 18px;
  --measure: 66ch;
  --wrap: 1180px;
  --wrap-narrow: 760px;
  --header-h: 4.75rem;
  color-scheme: light;

  /* Motion system. One curve family, one duration scale — the whole site
     should feel like a single hand moved it. Only transform and opacity are
     animated anywhere; both are composited, so nothing triggers layout or
     paint mid-animation. */
  --ease: cubic-bezier(.22, .7, .28, 1);        /* default: decisive, settles softly */
  --ease-drawer: cubic-bezier(.32, .72, 0, 1);  /* iOS-like, for panels sliding in */
  --ease-soft: cubic-bezier(.4, 0, .2, 1);      /* symmetric, for reversible states */
  --ease-out: cubic-bezier(.23, 1, .32, 1);     /* strong ease-out, for things that travel */
  --dur-1: 120ms;   /* micro — colour and small state changes */
  --dur-2: 200ms;   /* standard — hover and focus */
  --dur-3: 320ms;   /* medium — cards, images, panels */
  --dur-4: 560ms;   /* entrances */
  --dur-5: 700ms;   /* editorial — scroll reveals, narrative panel cross-fades */
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: var(--plum-950);
    --bg-rgb: 28 3 16;
    --bg-sunken: #150209;
    --bg-raised: #29061a;
    --bg-inverse: #390622;
    --surface-tint: #2f0619;
    --border: #4a1730;
    --border-strong: #6a2646;
    --text: #f6e9ef;
    --text-muted: #d5b8c6;
    --text-faint: #ab8b9a;
    --text-inverse: var(--white);
    --text-inverse-muted: #e6cdda;
    --link: var(--pink-300);
    --link-hover: var(--pink-100);
    --accent: var(--pink-400);
    --accent-contrast: var(--plum-950);
    --focus: var(--pink-300);
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.5);
    --shadow-md: 0 4px 14px rgb(0 0 0 / 0.55);
    --shadow-lg: 0 18px 44px rgb(0 0 0 / 0.65);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: var(--plum-950);
  --bg-rgb: 28 3 16;
  --bg-sunken: #150209;
  --bg-raised: #29061a;
  --bg-inverse: #390622;
  --surface-tint: #2f0619;
  --border: #4a1730;
  --border-strong: #6a2646;
  --text: #f6e9ef;
  --text-muted: #d5b8c6;
  --text-faint: #ab8b9a;
  --text-inverse: var(--white);
  --text-inverse-muted: #e6cdda;
  --link: var(--pink-300);
  --link-hover: var(--pink-100);
  --accent: var(--pink-400);
  --accent-contrast: var(--plum-950);
  --focus: var(--pink-300);
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.5);
  --shadow-md: 0 4px 14px rgb(0 0 0 / 0.55);
  --shadow-lg: 0 18px 44px rgb(0 0 0 / 0.65);
  color-scheme: dark;
}
/* --- Reset ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 1rem); }
/* There is deliberately no overflow-x on the root.
   There used to be: `html { overflow-x: clip }`, to stop the closed drawer —
   parked a full viewport width past the right edge — adding a horizontal
   scrollbar. The comment on it noted that `hidden` would break the sticky
   header and chose `clip` to avoid that. `clip` breaks it too, in WebKit: on
   iOS the header simply did not stick, so the site opened with no menu on
   screen. Chrome pinned it correctly, which is why it survived this long.
   It is gone rather than replaced because it was treating a symptom. The real
   causes of sideways scroll were a grid track that could not shrink and a
   reading measure applied as a fixed max-width to images; both are fixed
   above, and all 303 pages now measure clean at 375px and 320px with no clip
   at all. The closed drawer contributes nothing to the scrollable width on its
   own — it is position: fixed, and that was verified rather than assumed.
   If a horizontal scrollbar ever comes back, find what is actually wide.
   Do not reach for overflow on html or body: everything above the fold hangs
   off that header staying put. */
/* Reduced motion means fewer and gentler animations, not none. Killing every
   transition also kills the ones that explain state — a dropdown fading in, a
   focus ring arriving, a card acknowledging a hover. Those help. What has to
   go is movement: travel across the screen, scaling, and anything looping. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Looping and scroll-driven animation stops outright. */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    /* Keep transitions, but brisk — opacity and colour still communicate. */
    transition-duration: 150ms !important;
  }
  /* Neutralise the movement itself rather than the transition carrying it. */
  .card:hover,
  .card:hover .card__media img,
  .route:hover,
  .route:hover .route__arrow,
  .linklist a:hover,
  .montage li:hover img,
  .portrait:hover img,
  .portrait:focus-within img,
  .prose a:hover > img,
  .social a:hover,
  .social a:hover svg,
  .social-rail a:hover .social-rail__icon,
  .btn:active,
  .icon-btn:active,
  .filters__toggle:active {
    transform: none !important;
  }
  /* Panels change state by fading, not travelling. */
  .drawer[hidden], .drawer { transform: none !important; }
  .drawer[hidden] { opacity: 0; }
  .drawer { opacity: 1; transition: opacity 150ms linear, visibility 0s; }
  .search-dialog[hidden] .search-panel { transform: none !important; }
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
/* Default selection blue clashes with a plum palette. */
::selection { background: var(--pink-100); color: var(--plum-900); }
:root[data-theme="dark"] ::selection,
:root:not([data-theme="light"]) ::selection { background: var(--plum-700); color: var(--white); }
input, textarea { caret-color: var(--accent); }
input, button, textarea, select { font: inherit; color: inherit; }
/* Long unbreakable strings — in practice a bare URL pasted in as its own link
   text, one of which was 518px of "bmccancer.biomedcentral.com/articles/..."
   inside a 335px column.
   `anywhere` rather than `break-word` because only `anywhere` also lowers the
   element's min-content width: `break-word` wraps the line but still reports
   the unbroken width to its parent, which is how a single URL can force a grid
   track wider than the screen.
   Scoped to prose rather than set on body, and that scope is the point. On
   body it inherits into every control on the site, and "Donate" — one word, in
   the primary button, on every page — came out over three lines on a phone.
   `anywhere` is right for text somebody pasted in and wrong for a label we
   chose the width of. */
.prose, .lede, .card__excerpt, figcaption, dd, blockquote { overflow-wrap: anywhere; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
ul[class], ol[class] { list-style: none; padding: 0; }
:is(a, button, summary, input, [tabindex]):focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}
/* --- Typography ----------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  line-height: 1.12;
  letter-spacing: -0.015em;
  font-weight: 800;
  text-wrap: balance;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }
a { color: var(--link); text-underline-offset: 0.18em; text-decoration-thickness: from-font; }
a:hover { color: var(--link-hover); }
strong, b { font-weight: 700; }
/* Short quotation: a pull-out, set larger and lighter. */
blockquote {
  border-left: 3px solid var(--accent);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-5);
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--text-muted);
  font-style: normal;
}
blockquote p + p { margin-top: var(--sp-4); }
/* Long quotation: a document someone is meant to read and reuse — a template
   letter, a full statement. Body size, upright, on a panel that says
   "this block is quoted" without italicising several hundred words. */
blockquote.is-long {
  border-left: 0;
  border-radius: var(--radius);
  background: var(--bg-sunken);
  /* No accent bar across the top. It carried no meaning, clipped awkwardly
     against the rounded corners, and a coloured rail on a rounded card is the
     most recognisable tell there is. The tint and the hairline already say
     "this is quoted". */
  border: 1px solid var(--border);
  padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-5);
  font-size: var(--step-0);
  line-height: 1.7;
  color: var(--text);
  font-style: normal;
}
blockquote.is-long a { font-weight: 600; }
hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-7) 0; }
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; }
/* --- Layout helpers ------------------------------------------------------- */
.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
/* Between the phone breakpoint and 1280 the page gutter is 20px and the social
   rail is 34px, so anything running the full width of the wrap passed
   underneath it: on the pinned homepage panel the last word of a line
   disappeared behind the icons. The rail's footprint is reserved here so text
   stops short of it. Above 1280 the gutter is wide enough on its own. */
@media (min-width: 47rem) and (max-width: 1279px) {
  .wrap { padding-right: 3.5rem; }
}
.wrap--narrow { width: min(100% - 2.5rem, var(--wrap-narrow)); margin-inline: auto; }
.section { padding-block: var(--sp-8); }
/* A section straight after the page title does not need a full section's worth
   of air above it: the title band already has its own padding and a rule
   beneath it, so the two stacked left about 130px of nothing between the
   heading and the first line of text on every page. */
.page-head + .section { padding-top: var(--sp-6); }
.section--tight { padding-block: var(--sp-7); }
.section--sunken { background: var(--bg-sunken); }
.section--inverse { background: var(--bg-inverse); color: var(--text-inverse); }
.section--inverse h1, .section--inverse h2, .section--inverse h3 { color: var(--text-inverse); }
.section--inverse a { color: var(--pink-300); }
.section--inverse a:hover { color: var(--white); }
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: var(--sp-4); top: var(--sp-3); z-index: 200;
  transform: translateY(-250%);
  background: var(--plum-800); color: var(--white);
  padding: var(--sp-3) var(--sp-5); border-radius: var(--radius); font-weight: 600;
  transition: transform var(--dur-2) var(--ease);
}
.skip-link:focus { transform: translateY(0); color: var(--white); }
/* Gold survives in exactly one place: the exhibition's "now showing" tag,
   which is how their own campaign site uses it. */
.tag--current { background: var(--gold-500); color: var(--plum-950); font-weight: 700; }
.eyebrow {
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--sp-3);
}
.section--inverse .eyebrow { color: var(--pink-300); }
.lede { font-size: var(--step-1); line-height: 1.55; color: var(--text-muted); max-width: min(var(--measure), 100%); }
.section--inverse .lede { color: var(--text-inverse-muted); }
/* --- Buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--font-display); font-weight: 700; font-size: var(--step--1);
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.8em 1.5em; border-radius: var(--radius);
  border: 2px solid transparent; cursor: pointer; text-decoration: none;
  transition:
    background-color var(--dur-2) var(--ease),
    color var(--dur-2) var(--ease),
    border-color var(--dur-2) var(--ease),
    transform var(--dur-1) var(--ease);
}
.btn:active { transform: scale(0.97); }
.btn--primary { background: var(--magenta-600); color: var(--white); border-color: var(--magenta-600); }
.btn--primary:hover { background: var(--plum-700); border-color: var(--plum-700); color: var(--white); }
.btn--donate { background: var(--white); color: var(--plum-900); border-color: var(--white); }
.btn--donate:hover { background: var(--pink-100); border-color: var(--pink-100); color: var(--plum-900); }
/* On a light background the donate button needs the brand colour instead. */
.site-header .btn--donate,
.section:not(.section--inverse) .btn--donate,
.drawer .btn--donate { background: var(--magenta-600); color: var(--white); border-color: var(--magenta-600); }
.site-header .btn--donate:hover,
.section:not(.section--inverse) .btn--donate:hover,
.drawer .btn--donate:hover { background: var(--plum-700); border-color: var(--plum-700); color: var(--white); }
/* Pink fill, dark text. Measured at 10.18:1 against plum-950, so it clears AA
   comfortably and reads as a real button rather than an outline someone forgot
   to fill. Uses the site's own accent, so it adds emphasis without adding a
   colour. */
.btn--pink {
  background: var(--pink-300); color: var(--plum-950); border-color: var(--pink-300);
}
.btn--pink:hover {
  background: var(--pink-100); border-color: var(--pink-100); color: var(--plum-950);
}
.btn--ghost {
  background: transparent;
  color: var(--ghost-fg, var(--text));
  border-color: var(--ghost-border, var(--border-strong));
}
.btn--ghost:hover {
  color: var(--ghost-fg-hover, var(--accent));
  border-color: var(--ghost-border-hover, var(--accent));
  background: var(--ghost-bg-hover, transparent);
}
/* Every dark ground declares the colours its buttons should use. Custom
   properties inherit, so a button nested anywhere inside picks them up — no
   ancestor selector to forget when a new dark section is added later. */
.hero,
.section--inverse,
.cta-band,
.page-head--image,
.scrolly {
  --ghost-fg: var(--white);
  --ghost-border: rgb(255 255 255 / 0.55);
  --ghost-fg-hover: var(--white);
  --ghost-border-hover: var(--white);
  --ghost-bg-hover: rgb(255 255 255 / 0.12);
}
/* --- Signature motion -----------------------------------------------------
   The hero number counts up, the hero image drifts, and section rules draw
   themselves in. All of it is decoration layered on top of a page that is
   already complete and readable without JavaScript. */

/* A slow drift on the hero photograph: alive, never distracting. */
@keyframes hero-drift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(-1.5%, -1.5%, 0); }
}
.hero--image .hero__bg {
  /* No will-change. A running animation already promotes the element to its
     own layer; declaring it as well pins a full-bleed decoded bitmap in layer
     memory for the whole session, on every visit, for no extra smoothness. */
  animation: hero-drift 28s ease-in-out infinite alternate;
}
/* The "31" is the whole argument, so it gets the emphasis. Tabular figures
   plus a reserved two-digit box mean the count-up never reflows the layout. */
.hero__stat-number {
  font-variant-numeric: tabular-nums;
  display: block;
  min-width: 2ch;
  /* Scaled from the left edge so the figure grows into the card rather than
     drifting across it. */
  transform-origin: left center;
}
/* The count is a crescendo rather than a flat wait. --count runs 0 to 1 and is
   set by script from the number itself, so the figure grows and brightens with
   the value: the motion carries the data instead of decorating it. Thirty-one
   steps across a tenth of its size is a quarter-pixel each — a build you feel
   without being able to point at it. */
.hero__stat-number.is-counting {
  transform: scale(calc(0.9 + 0.1 * var(--count, 0)));
  opacity: calc(0.62 + 0.38 * var(--count, 0));
}
/* The landing is three beats, not a bounce. It gathers — accelerating away on
   the house exit curve, the way anything heavy loads before it moves — strikes
   fast, then spends the rest of the time settling on the enter curve. Fast in
   and slow out is what reads as mass. A symmetrical bounce reads as a toy, and
   that is the whole difference between this and something corny. The overshoot
   is under six per cent: at this size that is nearly five pixels of travel, and
   any more starts to look like a party trick.
   The weight is bought in the gather instead. Dropping to 0.95 rather than
   0.972 doubles the wind-up, so the strike swings through eleven per cent of
   the figure's size while the peak stays where it was — a harder landing that
   never goes further than it did. The gather gets a little longer with it: the
   same travel in the same 70ms would read as a twitch rather than a load. */
.hero__stat-number.is-landed { animation: figure-land var(--dur-5) both; }
@keyframes figure-land {
  0%   { transform: scale(1);    animation-timing-function: cubic-bezier(.4, 0, 1, 1); }
  13%  { transform: scale(0.95); animation-timing-function: cubic-bezier(.2, 0, .1, 1); }
  30%  { transform: scale(1.058); animation-timing-function: cubic-bezier(.16, 1, .3, 1); }
  100% { transform: scale(1); }
}
/* Follow-through. A heavy thing arriving moves what is around it, and it moves
   them *after* it — that lag is the entire difference between weight and
   bounce. The label and the note sit six pixels low while the count runs and
   rise into place a beat behind the strike. Their travel is transform only, so
   the text keeps its full contrast throughout: nothing here is ever dimmed for
   the sake of an effect. Stagger 90ms then 170ms, inside the 300ms cap. */
.hero__stat.is-counting .hero__stat-label,
.hero__stat.is-counting .hero__stat-note { transform: translateY(6px); }
.hero__stat.is-landed .hero__stat-label { animation: follow-rise var(--dur-3) var(--ease-out) 90ms both; }
.hero__stat.is-landed .hero__stat-note { animation: follow-rise var(--dur-3) var(--ease-out) 170ms both; }
@keyframes follow-rise {
  from { transform: translateY(6px); }
  to   { transform: translateY(0); }
}
/* Every class above is added by script, so with no JavaScript — or once the
   page has been open a while — the block simply sits in its settled state,
   which is the emphatic one and the one most visitors will see. */
@media (prefers-reduced-motion: reduce) {
  .hero__stat-number.is-counting,
  .hero__stat-number.is-landed,
  .hero__stat.is-counting .hero__stat-label,
  .hero__stat.is-counting .hero__stat-note,
  .hero__stat.is-landed .hero__stat-label,
  .hero__stat.is-landed .hero__stat-note {
    animation: none; transform: none; opacity: 1;
  }
}
.hero__stat {
  position: relative; overflow: hidden;
}
.hero__stat::before {
  content: ""; position: absolute; inset-inline: 0; top: 0; height: 3px;
  background: linear-gradient(90deg, var(--pink-300), var(--magenta-500), transparent);
  transform-origin: left;
  animation: rule-draw var(--dur-5) var(--ease) both 0.25s;
}
@keyframes rule-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* Section headings get a short rule that draws in when they arrive. */
.eyebrow { position: relative; display: inline-block; padding-bottom: 0.55rem; }
.eyebrow::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 2.5rem;
  background: currentColor; transform-origin: left; transform: scaleX(0);
  transition: transform var(--dur-4) var(--ease) 80ms;
}
.is-visible .eyebrow::after,
[data-reveal].is-visible .eyebrow::after,
.eyebrow.is-visible::after { transform: scaleX(1); }
/* Buttons lift rather than just recolour. */

@media (prefers-reduced-motion: reduce) {
  .hero--image .hero__bg { animation: none; transform: none; }
  .hero__stat::before { animation: none; transform: none; }
  .eyebrow::after { transition: none; transform: scaleX(1); }
}
/* --- Motion: content settles in as you scroll ----------------------------- */
/* Applied only once JS confirms IntersectionObserver support, so a no-JS or
   older browser simply shows everything. */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  /* Entering, so it uses the strong ease-out: fast off the mark, settling
     softly. --ease is the gentler curve kept for hover and colour. */
  /* 560ms, not 700. With the stagger on top, 700 put nearly a second between
     the first card of a row and the last, which on a grid you scroll past
     reads as sluggish rather than considered. */
  transition: opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.js-reveal [data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js-reveal [data-reveal] { opacity: 1; transform: none; transition: none; }
}
/* --- Header --------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  /* Opaque and border-free at rest. A 1px border renders as a soft sub-pixel
     smear on a scaled display, and a translucent bar sitting over a tinted
     page header adds a second tone step right beside it — together they read
     as a double line. The only boundary is the gradient below, once scrolled. */
  background: var(--bg);
  border-bottom: 0;
}
.site-header.is-stuck {
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
}
@supports not (backdrop-filter: blur(1px)) {
  .site-header.is-stuck { background: var(--bg); }
}
.site-header::after {
  content: ""; position: absolute; inset-inline: 0; top: 100%; height: 12px;
  /* A gradient, not a box-shadow. A shadow on a strip paints on every side, so
     its top edge draws a second hairline right under the border. */
  background: linear-gradient(to bottom, rgb(36 19 24 / 0.09), rgb(36 19 24 / 0));
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-soft);
  pointer-events: none;
}
:root[data-theme="dark"] .site-header::after,
:root:not([data-theme="light"]) .site-header::after {
  background: linear-gradient(to bottom, rgb(0 0 0 / 0.45), rgb(0 0 0 / 0));
}
.site-header.is-stuck::after { opacity: 1; }
@supports not (backdrop-filter: blur(1px)) { .site-header { background: var(--bg); } }
.site-header__bar {
  display: flex; align-items: center; gap: var(--sp-4);
  min-height: var(--header-h);
}
.brand { display: flex; align-items: center; gap: var(--sp-3); text-decoration: none; color: var(--text); flex: 0 0 auto; }
.brand img { width: 44px; height: 44px; border-radius: 50%; background: var(--white); }
.brand__name { font-family: var(--font-display); font-weight: 900; font-size: 1.15rem; letter-spacing: -0.02em; line-height: 1; }
.brand__tag { display: block; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint); margin-top: 2px; }
.site-header__actions { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }
.icon-btn {
  display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius);
  cursor: pointer; color: var(--text);
  transition: transform 160ms var(--ease), border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.icon-btn:hover { border-color: var(--accent); color: var(--accent); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 1.15rem; height: 1.15rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Primary navigation */
.nav { flex: 1 1 auto; }
.nav__list { display: flex; gap: var(--sp-1); list-style: none; margin: 0; padding: 0; }
.nav__link {
  display: block; padding: var(--sp-3) var(--sp-3);
  font-family: var(--font-display); font-weight: 600; font-size: 0.92rem;
  color: var(--text); text-decoration: none; border-radius: var(--radius);
  white-space: nowrap;
}
.nav__link:hover { color: var(--accent); background: var(--surface-tint); }
.nav__link[aria-current="page"], .nav__item--active > .nav__link { color: var(--accent); }
.nav__item--active > .nav__link::after {
  content: ""; display: block; height: 2px; background: var(--accent); margin-top: 3px; border-radius: 2px;
}
.nav__item { position: relative; }
/* A section heading is a link and a disclosure at once. Splitting them into two
   real controls means the label navigates and the chevron opens, so neither has
   to guess which the user meant. They are styled as one unit: the tint follows
   whichever half is hovered. */
/* The two halves have to be one shape. Centred, the chevron button came out
   17px shorter than the label beside it and sat lower, so the hover tint drew
   a step off the right-hand end instead of a pill. Stretched, they share an
   edge. */
.nav__item--has-panel { display: flex; align-items: stretch; }
.nav__item--has-panel > .nav__link { padding-right: var(--sp-1); }
.nav__disc {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 var(--sp-2) 0 0;
  background: none; border: 0; cursor: pointer; color: inherit;
  border-radius: var(--radius);
}
.nav__item--has-panel:hover > .nav__link,
.nav__item--has-panel:hover > .nav__disc { color: var(--accent); background: var(--surface-tint); }
.nav__item--has-panel > .nav__link { border-radius: var(--radius) 0 0 var(--radius); }
.nav__disc { border-radius: 0 var(--radius) var(--radius) 0; }
.nav__disc svg { width: 0.7em; height: 0.7em; transition: transform var(--dur-2) var(--ease); fill: none; stroke: currentColor; stroke-width: 3; }
.nav__item[data-open="true"] .nav__disc svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .nav__disc svg { transition: none; } }
.nav__panel {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 60;
  min-width: 20rem; padding: var(--sp-3);
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  list-style: none; margin: 0;
}
/* display:none cannot be animated, so the panel stays in the layer tree and
   is hidden with opacity + visibility instead. visibility keeps it out of the
   tab order and off the accessibility tree while it is closed. */
.nav__panel {
  opacity: 0;
  visibility: hidden;
  /* 0.985 was below the threshold where a scale reads as anything — it cost a
     transform and bought nothing. 0.96 is small enough to stay calm and large
     enough to say the panel came from the trigger above it. */
  transform: translateY(-6px) scale(0.96);
  transform-origin: top left;
  transition:
    opacity var(--dur-2) var(--ease-out),
    transform var(--dur-2) var(--ease-out),
    visibility 0s linear var(--dur-2);
}
.nav__item[data-open="true"] .nav__panel {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity var(--dur-2) var(--ease),
    transform var(--dur-2) var(--ease),
    visibility 0s;
}
@media (prefers-reduced-motion: reduce) {
  .nav__panel, .nav__item[data-open="true"] .nav__panel { transition: none; transform: none; }
}
.nav__panel a {
  display: block; padding: 0.7rem var(--sp-4); border-radius: var(--radius);
  color: var(--text); text-decoration: none; font-size: 0.95rem; line-height: 1.35;
  min-height: 2.75rem; display: flex; align-items: center;
}
.nav__panel a:hover { background: var(--surface-tint); color: var(--accent); }
.nav__panel .is-child a { padding-left: var(--sp-6); font-size: 0.9rem; color: var(--text-muted); }
.nav__panel .is-child a::before { content: "– "; color: var(--text-faint); }
.nav-toggle { display: none; }
@media (max-width: 1100px) {
  .nav { display: none; }
  .nav-toggle { display: inline-grid; }
  .site-header__actions { margin-left: auto; }
}
/* Mobile drawer */
.drawer {
  position: fixed; inset: 0; z-index: 150;
  background: var(--bg); overflow-y: auto;
  padding: var(--sp-4) 0 var(--sp-8);
  visibility: visible;
  transform: translateX(0);
  transition:
    transform var(--dur-3) var(--ease-drawer),
    visibility 0s;
}
/* [hidden] is display:none by default, and display cannot be transitioned.
   Override it and hide with visibility, which still removes the panel from the
   tab order and the accessibility tree — but can be animated. */
.drawer[hidden] {
  display: block;
  visibility: hidden;
  transform: translateX(100%);
  transition:
    transform var(--dur-3) var(--ease-drawer),
    visibility 0s linear var(--dur-3);
}
.drawer__top { display: flex; align-items: center; justify-content: space-between; min-height: var(--header-h); }
.drawer__list { list-style: none; margin: var(--sp-4) 0 0; padding: 0; }
.drawer__list > li { border-bottom: 1px solid var(--border); }
.drawer__list a { display: block; padding: var(--sp-4) 0; color: var(--text); text-decoration: none; font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); }
.drawer__list a:hover { color: var(--accent); }
.drawer__sub { list-style: none; margin: 0 0 var(--sp-4); padding: 0 0 0 var(--sp-4); border-left: 2px solid var(--border); }
.drawer__sub a { font-size: var(--step-0); font-weight: 500; font-family: var(--font-body); padding: var(--sp-2) 0; color: var(--text-muted); }
.drawer__sub .is-child a { padding-left: var(--sp-4); font-size: 0.92rem; }
.drawer__cta { margin-top: var(--sp-6); display: flex; flex-wrap: wrap; gap: var(--sp-3); }
/* --- Hero ----------------------------------------------------------------- */
.hero {
  position: relative; isolation: isolate;
  background: linear-gradient(120deg, var(--plum-900) 0%, var(--plum-800) 38%, var(--magenta-600) 100%);
  color: var(--white);
  padding-block: var(--sp-9);
  overflow: hidden;
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(ellipse at 80% 20%, rgb(236 63 142 / 0.5), transparent 60%);
}
/* Photographic hero: the image carries the warmth, the plum wash carries the
   brand and keeps the type at full contrast over any part of the picture. */
.hero__bg {
  position: absolute; inset: 0; z-index: -3;
  width: 100%; height: 100%; object-fit: cover; object-position: center 38%;
}
.hero--image { padding-block: clamp(2.25rem, 4vh, 3.5rem); }
/* A wider container gives the headline longer lines, which is what stops it
   wrapping to five and pushing the buttons past the fold. */
.hero .wrap { width: min(100% - 3rem, 1360px); }
/* Layer order matters here. Everything that tints the photograph lives on
   ::before; the fade to the page lives alone on ::after, which sits above it.
   With the fade underneath, the pink glow painted back over it and the join
   came out lighter on one side than the other. */
.hero--image::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background:
    /* Levels the bottom edge to one tone, so the fade above has a uniform base
       to dissolve from rather than a wash that varies across the width. */
    linear-gradient(to top, rgb(38 5 22 / 0.92) 0, rgb(38 5 22 / 0) 14rem),
    radial-gradient(ellipse at 78% 12%, rgb(236 63 142 / 0.34), transparent 62%),
    linear-gradient(100deg, rgb(28 3 16 / 0.94) 0%, rgb(43 5 25 / 0.86) 42%, rgb(68 7 41 / 0.62) 100%);
}
.hero--image::after { content: none; }
.hero--image { background: transparent; }
/* Getting this edge clean took three wrong techniques. What does not work:
   painting white over the photograph (every mid-tone goes through grey), or
   masking the photograph straight to transparent (same maths, same grey).
   What works is making the last stretch colour-to-colour:

     photograph  ->  brand wash  ->  flat plum  ->  page

   The photograph is gone before the fade begins, so the gradient that reaches
   the page is a two-colour ramp with nothing to muddy it. */
.hero--image .hero__bg {
  -webkit-mask-image: var(--photo-mask);
  mask-image: var(--photo-mask);
}
.hero--image::before {
  /* The fade to the page. Measured: dark plum going transparent over a white
     page has its midpoint at #95828c, chroma 0.027 — the grey haze that kept
     turning up at this join. Oklab only lifts it to 0.034, so the colour space
     was never the problem: nothing travels from a dark saturated colour to
     white without passing through greys.

     So it does not travel there directly. It climbs the brand's own scale on
     the way out, holding chroma near 0.18 through the middle, and every stop
     is opaque, so no light colour is ever composited over a dark one. */
  background:
    linear-gradient(to top,
      var(--white) 0,
      #fae0ec 1rem,
      #dd8bb4 2.2rem,
      #b03f73 3.6rem,
      #751841 5.2rem,
      #3f0a24 7rem,
      var(--plum-900) 9rem,
      rgb(43 5 25 / 0) 15rem),
    radial-gradient(ellipse at 78% 12%, rgb(236 63 142 / 0.34), transparent 62%),
    linear-gradient(100deg, rgb(28 3 16 / 0.94) 0%, rgb(43 5 25 / 0.86) 42%, rgb(68 7 41 / 0.62) 100%);
}
.hero--image {
  /* Photograph: fully cleared before the colour ramp starts. */
  --photo-mask: linear-gradient(to bottom,
    #000 0,
    #000 calc(100% - 11rem),
    rgb(0 0 0 / 0.72) calc(100% - 9rem),
    rgb(0 0 0 / 0.3) calc(100% - 7.5rem),
    rgb(0 0 0 / 0) calc(100% - 6.25rem));

  /* Flat plum to page colour — a clean two-colour ramp. */
  --wash-mask: linear-gradient(to bottom,
    #000 0,
    #000 calc(100% - 5rem),
    rgb(0 0 0 / 0.86) calc(100% - 3.9rem),
    rgb(0 0 0 / 0.6) calc(100% - 2.9rem),
    rgb(0 0 0 / 0.32) calc(100% - 1.9rem),
    rgb(0 0 0 / 0.12) calc(100% - 1rem),
    rgb(0 0 0 / 0) 100%);
}
/* Leave room below the buttons so the fade never washes over them. */
.hero--image { padding-bottom: clamp(4.5rem, 8vh, 6rem); }
.hero__grid { display: grid; gap: var(--sp-7); align-items: center; }
@media (min-width: 900px) {
  .hero__grid {
    grid-template-columns: 1.15fr 0.85fr;
    align-items: start;
    gap: clamp(2rem, 4vw, 4rem);
  }
  /* Drop the card to sit against the headline rather than the eyebrow above it. */
  .hero__stat { margin-top: 3rem; }
}
.hero__eyebrow {
  font-family: var(--font-display); font-weight: 700; font-size: var(--step--1);
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--pink-300); margin-bottom: var(--sp-4);
}
.hero h1 {
  /* Tie the display size to the height available as well as the width, so a
     short viewport gets a smaller headline instead of a clipped hero. */
  font-size: min(var(--step-5), 7.4vh); font-weight: 900; text-transform: uppercase;
  letter-spacing: -0.03em; line-height: 0.98; color: var(--white);
  max-width: 16ch;
}
/* Each clause gets its own line: the sentence is three beats and reading it as
   three lines is the point. The two are different pinks so the second does not
   read as the first broken in half.

   The second is LIGHTER, not deeper, and that was measured rather than chosen.
   Against the lightest part of the photograph behind this text (#763457), the
   deeper pink-400 lands at 2.36:1, under the 3:1 that large text needs.
   Lifting instead of dropping keeps it at 4.5:1 and lets the last beat land
   hardest, which is the right reading anyway. */
.hero h1 em { font-style: normal; }
.hero__beat { color: var(--pink-300); }
.hero__beat--last { color: #ff9ccd; }
.hero__lede { font-size: var(--step-0); line-height: 1.55; color: #f3dfe9; margin-top: var(--sp-4); max-width: 52ch; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.hero__stat {
  background: rgb(0 0 0 / 0.28); border: 1px solid rgb(255 255 255 / 0.18);
  border-radius: var(--radius-lg); padding: var(--sp-5) var(--sp-6);
  backdrop-filter: blur(4px);
}
.hero__stat-number {
  font-family: var(--font-display); font-weight: 900; font-size: clamp(3rem, 7vw, 4.5rem);
  line-height: 0.9; color: var(--pink-300); letter-spacing: -0.04em;
}
.hero__stat-label { font-size: var(--step-0); color: #f3dfe9; margin-top: var(--sp-2); text-wrap: balance; }
.hero__stat-note { font-size: var(--step--1); color: #d9b9cb; margin-top: var(--sp-4); }

/* Tappable controls: press instantly, release eases back.
   The base transition eases transform over --dur-1, which is right on the way
   back up but wrong on the way down: it delays the one frame the user is
   watching most closely, and a press that lags reads as a slow interface.
   Zeroing the duration only on :active gives the asymmetry a press wants.
   touch-action: manipulation removes the browser's double-tap-zoom wait, worth
   up to 300ms of dead time on the first tap of any control on a phone. */
.btn, .icon-btn, .filters__toggle, .social a, .social-rail a,
.c-disclosure > summary, .nav__toggle, .pill, .topic {
  touch-action: manipulation;
}
.btn:active, .icon-btn:active, .filters__toggle:active,
.social a:active, .tmm_scblock a:active {
  transition-duration: 0s;
}


/* --- Forms ----------------------------------------------------------------
   The site had none. Three hundred pages, no way to join, subscribe or get in
   touch except a mailto: link that goes nowhere on a phone without a mail
   client configured.

   Label above the input, help below it, error below that. Never a placeholder
   standing in for a label: a placeholder vanishes the moment someone types, so
   anyone interrupted mid-form loses the question. Every colour here was
   measured against the page rather than picked: label 18.45:1, help 6.79:1,
   border 3.30:1. */
.form { display: grid; gap: var(--sp-5); max-width: 34rem; margin-block: var(--sp-6); }
.form__intro { color: var(--text-muted); margin: 0; }
.form__field { display: grid; gap: 0.4rem; }
.form__label { font-weight: 600; color: var(--text); }
.form__required { color: var(--magenta-600); margin-left: 0.15em; }
.form__help { font-size: var(--step--1); color: var(--text-muted); margin: 0; }
.form__control {
  font: inherit; color: var(--text); background: var(--bg);
  border: 1px solid var(--border-control); border-radius: var(--radius);
  padding: 0.7em 0.8em; width: 100%;
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.form__control:hover { border-color: var(--text-muted); }
.form__control:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-color: var(--accent);
}
/* A tick box and its label read as one line, and the box keeps a real target. */
.form__field--check { grid-template-columns: auto 1fr; align-items: start; gap: 0.6rem; }
/* The box is drawn at 18px because that is the size it should look, and given
   a 44px target because that is the size a thumb needs. WCAG 2.5.5 asks for
   44 and a tick box is the control people miss most: the one thing standing
   between someone and joining. The label is bound with for= so it is tappable
   too, but the box itself has to be hittable on its own. */
.form__check {
  width: 1.15rem; height: 1.15rem; margin-top: 0.15rem;
  accent-color: var(--accent); position: relative;
}
.form__check::before {
  content: ""; position: absolute;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}
.form__label--inline { font-weight: 400; color: var(--text-muted); }
/* The honeypot is for robots, so it leaves the page for everyone else without
   using display:none, which some bots check for. */
.form__pot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.form button[type="submit"] { justify-self: start; }
@media (prefers-reduced-motion: reduce) { .form__control { transition: none; } }

/* The reply to a submission. Both start hidden and only one is ever shown. */
.form__done, .form__error {
  border-radius: var(--radius); padding: var(--sp-5); margin-block: var(--sp-6);
  max-width: 34rem;
}
.form__done { background: var(--surface-tint); border: 1px solid var(--accent); }
.form__done-title { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: var(--step-1); color: var(--text); }
.form__error { background: var(--bg-sunken); border: 1px solid var(--border-control); }
.form__error p { margin: 0; color: var(--text); }
.form__done:focus-visible, .form__error:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* On a phone the form is the page: full width, and a submit button wide enough
   to hit with a thumb rather than a target floating at the left margin. */
@media (max-width: 560px) {
  .form { gap: var(--sp-4); }
  .form button[type="submit"] { justify-self: stretch; justify-content: center; }
}

/* --- Page header (interior pages) ---------------------------------------- */
.page-head { background: var(--bg-sunken); border-bottom: 1px solid var(--border); padding-block: var(--sp-7) var(--sp-6); }
.page-head h1 { max-width: 22ch; }
.page-head .lede { margin-top: var(--sp-4); }
/* A page's call to action, sitting under the heading where it is in reach
   before any scrolling. Given its own line rather than floated beside the
   heading, so a long label wraps into space instead of into the title. */
.page-head__action { margin-top: var(--sp-5); }
.btn__away { margin-left: 0.4em; font-size: 0.85em; line-height: 1; }
/* When a page has a featured image, it becomes the banner behind the title. */
.page-head--image {
  position: relative; isolation: isolate; border-bottom: 0;
  padding-block: clamp(var(--sp-7), 7vw, var(--sp-9));
  color: var(--white);
  background: var(--plum-900);
}
.page-head--image h1 { color: var(--white); max-width: 20ch; }
.page-head--image .lede { color: #f0dbe6; }
.page-head--image .breadcrumb ol { color: #c9a6b8; }
.page-head--image .breadcrumb a { color: #f0dbe6; }
.page-head--image .breadcrumb a:hover { color: var(--pink-300); }
.page-head--image .breadcrumb li + li::before { color: rgb(255 255 255 / 0.35); }
.page-head__bg {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: center 40%;
}
.page-head--image::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(95deg, rgb(28 3 16 / 0.93) 0%, rgb(43 5 25 / 0.82) 48%, rgb(68 7 41 / 0.58) 100%);
}
.page-head--image { padding-bottom: clamp(2.75rem, 4.5vh, 3.75rem); }
.breadcrumb { margin-bottom: var(--sp-4); font-size: var(--step--1); }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; margin: 0; padding: 0; color: var(--text-faint); }
.breadcrumb li + li::before { content: "/"; margin-right: var(--sp-2); color: var(--border-strong); }
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--accent); text-decoration: underline; }
/* --- Prose (all migrated page + post bodies) ------------------------------ */
.prose { max-width: none; font-size: var(--step-0); }
/* Text is held to a comfortable line length one element at a time, rather than
   by capping the container — so a full-width child can opt out cleanly. */
/* min(), not the measure alone. This selector is more specific than the global
   `img { max-width: 100% }`, so it replaces that cap rather than adding to it —
   and a fixed 76ch is no cap at all on a phone. Text did not show it, because a
   paragraph shrinks to its container anyway; a replaced element does not, so an
   <img> placed straight into prose sat at 714px inside a 335px column and took
   the whole page sideways with it. Anything given a measure here has to be able
   to give it back. */
.prose > * { max-width: min(var(--measure), 100%); }
.prose > * + * { margin-top: var(--sp-4); }
.prose h2 { font-size: var(--step-2); margin-top: var(--sp-7); }
.prose h3 { font-size: var(--step-1); margin-top: var(--sp-6); }
.prose h4 { font-size: var(--step-0); text-transform: uppercase; letter-spacing: 0.06em; margin-top: var(--sp-5); color: var(--text-muted); }
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li + li { margin-top: var(--sp-2); }
/* Images line up with the text, not with the column. margin-inline: auto
   centred every picture inside a container wider than the measure, so an image
   sat 51px to the right of the paragraph above it: not enough to look
   deliberate, just enough to look wrong. Flush left is the whole point of a
   left-aligned measure. */
.prose img { border-radius: var(--radius); }
.prose figcaption { max-width: min(var(--measure), 100%); }
.prose figure { margin-block: var(--sp-6); }
.prose figcaption { font-size: var(--step--1); color: var(--text-faint); margin-top: var(--sp-2); }
/* A linked image should feel clickable. */
.prose a:has(> img) { display: inline-block; border-radius: var(--radius); overflow: hidden; }
.prose a > img { transition: transform var(--dur-3) var(--ease); }
.post-hero { margin: 0 0 var(--sp-7); border-radius: var(--radius-lg); overflow: hidden; background: var(--bg-sunken); }
.post-hero img { width: 100%; aspect-ratio: 16/9; object-fit: cover; border-radius: 0; }
/* A low-resolution upload keeps its own size, centred on a tinted panel, rather
   than being stretched to fill the column. */
.post-hero--contained {
  display: grid; place-items: center;
  padding: var(--sp-6);
  background: var(--surface-tint);
  border: 1px solid var(--border);
}
.post-hero--contained img {
  width: auto; max-width: min(100%, 480px);
  aspect-ratio: auto; object-fit: contain;
  border-radius: var(--radius);
}
.prose a { font-weight: 500; }
/* Was a heading in the source, but reads as an emphasised opening line. */
.prose .lead {
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--text);
  font-weight: 500;
}
.prose table { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
.prose :is(th, td) { border: 1px solid var(--border); padding: var(--sp-2) var(--sp-3); text-align: left; }
.prose th { background: var(--bg-sunken); font-weight: 700; }
.prose--wide { max-width: none; }
.table-scroll { overflow-x: auto; }
.c-embed { position: relative; padding-top: 56.25%; border-radius: var(--radius); overflow: hidden; background: var(--bg-sunken); }
.c-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* An audio player is a fixed-height control, not a 16:9 frame. */
.c-embed--audio { padding-top: 0; height: 11.5rem; background: transparent; }
/* Dashboards and boards need height, but nothing like a video's. */
.c-embed--panel { padding-top: 0; height: clamp(24rem, 55vh, 34rem); }
/* --- Video, buttons, columns ------------------------------------------- */

/* Self-hosted video, as opposed to an embed. Not ratio-locked the way
   .c-embed is: an embed has to reserve space for an iframe whose contents it
   cannot measure, but a <video> reports its own dimensions, and forcing a 4:3
   archive clip into 16:9 spends a third of the screen on black bars. */
.c-video { margin-block: var(--sp-5); }
.c-video__player {
  display: block; width: 100%; height: auto;
  border-radius: var(--radius); background: var(--bg-sunken);
}
/* Only ever seen if the browser cannot play the file at all, in which case it
   is the download link and should read as text, not as a caption. */
.c-video__fallback { padding: var(--sp-4); font-size: var(--step--1); }

/* A row of buttons. Wraps rather than scrolls, and the gap is the one already
   used between paragraphs so a call to action sits in the rhythm of the page
   instead of floating in its own pocket of space. */
.c-buttons {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  margin-block: var(--sp-5);
}

/* Columns of ordinary prose. The measure is lifted here and only here: two
   columns inside a 66ch limit are 33ch each, which is a newspaper column, not
   a readable line. Below 46rem they stack, because two columns on a phone are
   one column with extra steps. */
.prose > .c-columns { max-width: none; }
.c-columns {
  display: grid; gap: var(--sp-5) var(--sp-6);
  margin-block: var(--sp-5);
}
.c-columns__col > * + * { margin-top: var(--sp-4); }
@media (min-width: 46em) {
  .c-columns { grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); }
  .c-columns[data-count="3"] { --cols: 3; }
  .c-columns[data-count="4"] { --cols: 4; }
  /* An asymmetric split is two columns whatever the count says, because the
     ratio is the whole point of asking for it. */
  .c-columns[data-layout="wide-left"] { grid-template-columns: 3fr 2fr; }
  .c-columns[data-layout="wide-right"] { grid-template-columns: 2fr 3fr; }
}

/* A picture grid. The renderer has emitted this class since the migration and
   nothing ever styled it, so every gallery on the site has been rendering as a
   stack of full-width images. */
.prose > .prose-grid { max-width: none; }
.prose-grid {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
  margin-block: var(--sp-5);
}
.prose-grid img { width: 100%; height: 100%; object-fit: cover; }

.c-disclosure {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-raised); padding: 0; overflow: hidden;
}
.c-disclosure + .c-disclosure { margin-top: var(--sp-3); }
.c-disclosure > summary {
  cursor: pointer; padding: var(--sp-4) var(--sp-5); list-style: none;
  font-family: var(--font-display); font-weight: 700; font-size: var(--step-0);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
}
.c-disclosure > summary::-webkit-details-marker { display: none; }
/* The marker turns rather than being swapped for a different character: a
   plus rotated 45 degrees is a close cross, so one glyph covers both states
   and the change can be seen happening. */
.c-disclosure > summary::after {
  content: "+"; font-size: 1.4em; line-height: 1; color: var(--accent); flex: 0 0 auto;
  transition: transform var(--dur-2) var(--ease);
}
.c-disclosure[open] > summary::after { transform: rotate(45deg); }
/* Opening one of these used to put the content on screen instantly, which is
   the one place on the site where something appeared out of nothing. The
   answer wipes down from the summary it belongs to. clip-path and opacity are
   both composited, so this costs no layout.

   Closing stays immediate on purpose: `details` removes its content from the
   box tree the moment it closes, so there is nothing left to animate out
   without holding the element open from script. Dismissing also reads as
   decisive, which is the right feel for putting something away. */
@media (prefers-reduced-motion: no-preference) {
  .c-disclosure[open] > .c-disclosure__body {
    animation: disclosure-open var(--dur-3) var(--ease-out) both;
  }
  @keyframes disclosure-open {
    from { opacity: 0; clip-path: inset(0 0 100% 0); }
    to   { opacity: 1; clip-path: inset(0 0 0 0); }
  }
}
@media (prefers-reduced-motion: reduce) {
  .c-disclosure > summary::after { transition: none; }
}
.c-disclosure > summary:hover { background: var(--surface-tint); }
.c-disclosure__body { padding: 0 var(--sp-5) var(--sp-5); }
.c-disclosure__body > * + * { margin-top: var(--sp-4); }
.c-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--sp-3); list-style: none; padding: 0; }
.c-gallery img { border-radius: var(--radius); width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.c-card {
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
}
.c-card__media img { width: 100%; aspect-ratio: 16/10; object-fit: cover; border-radius: 0; }
.c-card__body { padding: var(--sp-5); }
/* --- Profile grid ---------------------------------------------------------
   Fifty-nine people, each previously a full-width portrait stacked above a
   full-width disclosure. As a grid the portraits are sized like portraits and
   the page becomes scannable — you can find a person rather than scroll past
   everyone before them. Breaks out of the reading measure, because a grid of
   faces is not prose. */
.profile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
  gap: var(--sp-5);
  /* Fills its column — never the viewport, or it slides under the sidebar. */
  max-width: none;
  margin-block: var(--sp-6);
}
.profile {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-raised);
  overflow: hidden;
}
/* The card sheds its own frame — the .profile wrapper carries it now. */
.profile .c-card {
  border: 0;
  border-radius: 0;
  background: transparent;
}
.profile .c-card__media img { aspect-ratio: 1 / 1; }
.profile .c-card__body { padding: var(--sp-4) var(--sp-4) var(--sp-2); }
.profile .c-card__title { font-size: var(--step-0); margin-bottom: 0.15rem; }
.profile .c-card__text {
  font-size: 0.85rem;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.profile .c-disclosure {
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  margin-top: auto;
}
.profile .c-disclosure > summary {
  padding: var(--sp-3) var(--sp-4);
  font-size: 0.85rem;
}
.profile .c-disclosure__body {
  padding: 0 var(--sp-4) var(--sp-4);
  font-size: 0.92rem;
}
/* --- Grids and cards ------------------------------------------------------ */
.grid { display: grid; gap: var(--sp-5); }
.grid--3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr)); }
.card {
  position: relative;
  display: flex; flex-direction: column;
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
  transition: transform var(--dur-3) var(--ease), border-color var(--dur-2) var(--ease);
}
/* The lift shadow lives on its own layer, so hovering never repaints the card. */
.card::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; box-shadow: var(--shadow-lg);
  opacity: 0; transition: opacity var(--dur-3) var(--ease);
  pointer-events: none;
}
.card:hover { border-color: var(--border-strong); }
.card:hover::after { opacity: 1; }
.card__media { background: var(--bg-sunken); overflow: hidden; }
.card__media img { width: 100%; aspect-ratio: 16/9; object-fit: cover; transition: transform var(--dur-3) var(--ease); }
/* Feature cards wash the image toward the brand so a grid of very different
   photographs still reads as one set. */
.card--feature .card__media--tinted { position: relative; }
.card--feature .card__media--tinted::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgb(68 7 41 / 0.12), rgb(68 7 41 / 0.42));
  mix-blend-mode: multiply; pointer-events: none;
}
.card--feature .card__media img { aspect-ratio: 16/10; }
/* Posts with no image at all. Rather than a stand-in graphic — which reads as
   a failed image — the card leads with its type and takes a brand rule. */
.card--text { border-top: 3px solid var(--accent); }
.card--text .card__body { padding-top: var(--sp-5); gap: var(--sp-3); }
.card--text .card__title { font-size: var(--step-2); }
.card--text .card__excerpt {
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical;
  overflow: hidden;
}
.card__body { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); flex: 1; }
.card__title { font-size: var(--step-1); line-height: 1.2; }
.card__title a { color: inherit; text-decoration: none; }
.card__title a::after { content: ""; position: absolute; inset: 0; }
.card { position: relative; }
.card__title a:hover { color: var(--accent); }
.card__meta { font-size: var(--step--1); color: var(--text-faint); display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.card__excerpt { color: var(--text-muted); font-size: 0.95rem; }
.card__more { margin-top: auto; padding-top: var(--sp-3); font-family: var(--font-display); font-weight: 700; font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.06em; color: var(--accent); }
.tag {
  display: inline-block; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 0.25em 0.7em; border-radius: 100px;
  background: var(--surface-tint); color: var(--accent); text-decoration: none;
  border: 1px solid transparent;
}
a.tag:hover { border-color: var(--accent); }
/* Link list — used for section indexes and the footer sitemap. */
.linklist { list-style: none; padding: 0; display: grid; gap: var(--sp-2); }
.linklist a {
  display: flex; align-items: center; gap: var(--sp-3); min-height: 3.25rem;
  padding: var(--sp-3) var(--sp-5); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-raised); text-decoration: none; color: var(--text); font-weight: 500;
  transition: border-color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.linklist a:hover { border-color: var(--accent); color: var(--accent); background: var(--surface-tint); }
.linklist a::after { content: "→"; margin-left: auto; color: var(--text-faint); }
.linklist a:hover::after { color: var(--accent); }
/* --- Section heading: title left, standfirst right ------------------------ */
/* Stacked, not split. A big headline on the left with its explainer floating
   in a column to the right is one of the most recognisable generic layouts
   there is, and here it also read badly: "Three fronts, one goal" is four
   words, so its column sat almost empty beside a full paragraph. A section
   carries one message; the heading leads and the sentence follows it. */
.section-head { display: grid; gap: var(--sp-4); align-items: start; }
.section-head > * { max-width: min(var(--measure), 100%); }
.section-head h2 { max-width: 22ch; }
@media (min-width: 900px) {
  .section-head { gap: var(--sp-4); }
  .section-head .lede { margin: 0; }
}
/* --- Portrait montage (homepage campaign band) ---------------------------- */
.feature-band__grid { display: grid; gap: var(--sp-7); align-items: center; }
@media (min-width: 950px) { .feature-band__grid { grid-template-columns: 1fr 1fr; } }
.montage {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2);
  list-style: none; padding: 0; margin: 0;
}
.montage li { position: relative; overflow: hidden; border-radius: var(--radius); }
.montage img {
  width: 100%; aspect-ratio: 3/4; object-fit: cover;
  transition: transform var(--dur-3) var(--ease);
}
/* Tinting through an overlay keeps the interaction on the compositor. Animating
   a filter would force the image to be re-rasterised on every frame. */
.montage li::after {
  content: ""; position: absolute; inset: 0;
  background: var(--plum-800); mix-blend-mode: color;
  opacity: 0.3; transition: opacity var(--dur-3) var(--ease);
  pointer-events: none;
}
.montage li:hover::after { opacity: 0; }
.montage li:nth-child(n+9) { display: none; }
@media (min-width: 560px) { .montage li:nth-child(n+9) { display: block; } }
/* --- Scrollytelling band --------------------------------------------------
   A pinned image with text panels moving over it. Built on position: sticky,
   so the pinning is the browser's own scrolling — no scroll listener, no
   jank. JavaScript only toggles which panel is emphasised; with it disabled,
   or under reduced-motion, the whole thing degrades to stacked sections that
   read in exactly the same order. */
.scrolly { position: relative; background: var(--plum-950); color: var(--white); }
.scrolly__media {
  position: sticky; top: 0; z-index: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
}
.scrolly__media > img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.08);
  /* 700ms, the hero token. This is the fallback for browsers without
     scroll-driven animation, so it is a one-shot settle rather than the ambient
     drift it reads as below — 1600ms was well over the duration ceiling for
     something that happens once and then stops. */
  transition: transform var(--dur-5) var(--ease-soft);
}
.scrolly.is-active .scrolly__media > img { transform: scale(1); }
/* Where scroll-driven animation is available, let the image drift with the
   scroll instead of settling once — the parallax is what sells the pinning. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .scrolly__media > img {
      transition: none;
      animation: scrolly-drift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    @keyframes scrolly-drift {
      from { transform: scale(1.12) translate3d(0, -1.5%, 0); }
      to   { transform: scale(1.02) translate3d(0, 1.5%, 0); }
    }
  }
}
/* --- The thirty-one, pinned behind the copy -------------------------------
   Sits above the photograph and its scrim, on the left half the copy leaves
   free. Hidden below 900px, where the copy already takes the full width and
   there is no free half to fill. */
.scrolly__art {
  position: absolute; inset: 0; z-index: 2;
  display: none;
  align-content: center;
  /* The copy sits in the right half and the artwork is on a separate layer, so
     nothing stops them overlapping except this: the artwork is not allowed
     into the half the words occupy. */
  /* Both edges are decided, not left to chance. The left one is the page's own
     margin — the same gutter .wrap uses — so the portraits line up with every
     other block on the site instead of floating at an arbitrary inset. The
     right one is a channel wide enough to read as a column break: the grid was
     ending 25px from the headline, which looks like a collision rather than a
     layout. */
  /* One measure, used on both sides. The space from the page edge to the first
     portrait and the space from the last portrait to the headline are the same
     number, so the block reads as a column that was placed rather than one that
     ended up where it ended up. Two different clamps had them agreeing at
     1280 and drifting apart by 16px at 1920, which is exactly the kind of
     almost-aligned that looks like an accident. */
  --art-space: clamp(1.5rem, 5vw, 6rem);
  --art-gutter: var(--art-space);
  /* The channel is wider than the outer margin, which is the usual
     relationship between a column gap and a page edge: the gap that separates
     two things has more work to do than the one that just holds a block off
     the edge. Equal on both sides read as tight the moment the copy came near
     the last column. */
  /* A clear gap, not an overlap. Running the grid under the copy read fine at
     a wide window, where only the edge of the last column sat behind the
     headline. Narrow the window and the same rule put whole sentences across
     women's faces: the text became unreadable and the portraits became a
     texture behind it. The channel stays positive so the two halves never
     touch at any width. */
  --art-channel: calc(var(--art-space) * 1.5);
  /* Where the copy's left edge actually falls: the window, less the wrap's
     right gutter, less its measure. Deriving the channel from the real edge
     rather than from a percentage is what makes the gap the same on every
     screen instead of collapsing to 25px on wide ones. */
  --copy-left: calc(100vw - max(1.25rem, (100vw - var(--wrap)) / 2) - 34rem);
  padding: calc(var(--header-h) + 1.25rem) 0 2rem var(--art-gutter);
  pointer-events: none;
  /* One cell size, derived from whichever runs out first — the width the left
     half can spare, or the height five rows need. Sizing on width alone cropped
     the top and bottom rows: at a narrower window the block grew taller than
     the pinned area and the section's own overflow ate them.

     Three things come out of the viewport height before the portraits get any.
     The header, because it is sticky and sits over the top of the pinned media,
     so the visible area is a header shorter than the viewport — that is what
     was hiding the first row. The padding. And the name and button anchored at
     the bottom: miss that one and on a 650px laptop the caption lands on the
     final row.

     Eight to a row rather than seven, because height was the binding
     constraint: eight columns is four rows instead of five, and the row it
     saves is what lets every face be half again as large. Thirty-one over four
     rows leaves a centred seven at the bottom.
     5.32 is four rows of 323:430 plus their gaps; the width term is the same
     sum across eight columns, in the 48% of the window the copy leaves free. */
  --cell: min(
    7rem,
    calc((var(--copy-left) - var(--art-gutter) - var(--art-channel) - 35px) / 8),
    calc((100svh - var(--header-h) - 12rem) / 5.4)
  );
}
/* Below this there is no left half to speak of — the copy needs the full width,
   and 1100px is where the desktop navigation appears for the same reason. */
@media (min-width: 1100px) { .scrolly__art { display: grid; } }
/* Flex, not grid: thirty-one is prime, so a grid leaves a ragged last row
   hanging to one side. Centring every row makes the short one read as
   composition rather than leftovers. */
.scrolly__faces {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 5px;
  /* Width follows the cell rather than the other way round. A percentage width
     would let flex-wrap fit an eighth face onto a row the moment the cells
     shrank, quietly changing five rows into four and breaking the arithmetic
     that keeps the block inside the viewport. */
  max-width: calc(8 * var(--cell) + 35px);
  /* Hug the gutter. Centring inside the padded box made the left inset depend
     on whatever width was left over, which is how one edge ended up deliberate
     and the other accidental. */
  margin-inline: 0 auto;
}
.scrolly__face {
  width: var(--cell); height: auto; aspect-ratio: 323 / 430;
  object-fit: cover; display: block;
  opacity: 0; transform: scale(0.94) translateY(8px);
  /* Duotone into the brand: greyscale for an even base, then sepia and a hue
     rotation carry it to plum, so the faces sit inside the palette instead of
     looking like a contact sheet dropped onto it. The filter is static — only
     opacity and transform ever animate. */
  filter: grayscale(1) contrast(1.06) sepia(1) hue-rotate(276deg) saturate(1.7) brightness(0.92);
  transition:
    opacity var(--dur-5) var(--ease-out),
    transform var(--dur-5) var(--ease-out);
}
/* Nothing at all while the campaign is being introduced — the first panel is a
   title card and the left half belongs to the photograph. A single portrait
   there read as a stray image rather than a beat, and because the other thirty
   still hold their space it sat stranded in the top corner rather than centred.
   Empty, then thirty-one on the number that names them, is the stronger move. */
.scrolly[data-panel="2"] .scrolly__face,
.scrolly[data-panel="3"] .scrolly__face { opacity: 1; transform: none; }
/* Cascade by row. Per-item delays drew a diagonal wipe across the block; by row
   it reads as the group arriving. Three steps of 80ms is 240ms, inside the 300ms cap. */
.scrolly__face:nth-child(n+9)  { transition-delay: 80ms; }
.scrolly__face:nth-child(n+17) { transition-delay: 160ms; }
.scrolly__face:nth-child(n+25) { transition-delay: 240ms; }
/* The last panel asks for a chance to live. The crowd recedes and one woman
   stays — a statistic becoming a person, which is the campaign's whole argument. */
.scrolly[data-panel="3"] .scrolly__face { opacity: 0.14; transition-delay: 0ms; }
.scrolly[data-panel="3"] .scrolly__face.is-kept {
  opacity: 1; filter: none; transform: scale(1.14);
  outline: 2px solid var(--pink-300); outline-offset: 2px;
}
/* Anchored to the bottom rather than stacked under the portraits. In the flow
   it added its own height to the centred block, so the arithmetic that keeps
   five rows inside the viewport was short by the height of a name and a button
   — and the top row went back behind the header. */
.scrolly__kept {
  position: absolute;
  left: clamp(1.5rem, 4vw, 3rem);
  bottom: 2rem;
  margin: 0; max-width: 22rem;
  opacity: 0; transform: translateY(6px);
  transition: opacity var(--dur-3) var(--ease-out) 350ms, transform var(--dur-3) var(--ease-out) 350ms;
}
.scrolly__kept b { display: block; color: var(--white); font-family: var(--font-display); font-size: 1.15rem; letter-spacing: -0.01em; }
.scrolly__kept span { display: block; color: #ffd9ec; font-size: 0.9rem; margin-top: 0.25rem; line-height: 1.5; }
/* A button, not a QR code. The code is how the figures work in a room; on a
   phone nobody scans the screen they are already holding. The artwork layer
   ignores pointer events so it never sits between the reader and the copy —
   the one thing in it that is actually clickable has to opt back in. */
.scrolly__kept .btn { margin-top: var(--sp-4); pointer-events: auto; }
.scrolly[data-panel="3"] .scrolly__kept { opacity: 1; transform: none; }
/* No script, or reduced motion: the whole group simply sits there. */
html:not(.js-reveal) .scrolly__face,
.scrolly:not([data-panel]) .scrolly__face { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .scrolly__face, .scrolly__kept { transition: none; opacity: 1; transform: none; }
  .scrolly__kept { opacity: 1; }
}
.scrolly__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgb(28 3 16 / 0.58) 0%, rgb(28 3 16 / 0.34) 40%, rgb(28 3 16 / 0.72) 100%),
    linear-gradient(90deg, transparent 30%, rgb(28 3 16 / 0.55) 100%);
}
/* Pull the panels back over the pinned image. */
.scrolly__panels { position: relative; z-index: 1; margin-top: -100vh; margin-top: -100svh; }
.scrolly__panel {
  min-height: 68vh; min-height: 68svh;
  display: grid; align-content: center;
  padding-block: var(--sp-7);
}
/* The first panel starts under the pinned image, so it needs a full screen to
   sit in; the rest can be tighter. */
.scrolly__panel:first-child { min-height: 100vh; min-height: 100svh; }
.scrolly__copy {
  max-width: 34rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.scrolly__panel > .wrap {
  /* Inactive panels are fully hidden: at 68vh two panels can be on screen at
     once, and a faint second heading reads as a bug rather than a transition. */
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-5) var(--ease-soft), transform var(--dur-5) var(--ease-soft);
}
.scrolly__panel.is-current > .wrap { opacity: 1; transform: none; }
.scrolly__copy > .eyebrow { color: var(--pink-300); margin-bottom: var(--sp-3); }
.scrolly__copy > h2 { color: var(--white); font-size: var(--step-4); }
.scrolly__copy > p { color: #f0dbe6; margin-top: var(--sp-4); font-size: var(--step-1); line-height: 1.5; }
.scrolly__copy > p.scrolly__figure {
  font-family: var(--font-display); font-weight: 900;
  font-size: clamp(3.5rem, 11vw, 7rem); line-height: 0.85;
  color: var(--pink-300); letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  margin-top: 0; margin-bottom: var(--sp-4);
}
.scrolly__copy .hero__actions { margin-top: var(--sp-6); }
/* Right-align the panels so the photograph stays readable on the left. */
/* Push the copy to the right half so the photograph stays legible on the left,
   while the .wrap gutter still guarantees breathing room at the edge. */
@media (min-width: 900px) {
  .scrolly__copy { margin-left: auto; }
}
/* No JavaScript, or reduced motion: stop pinning and show every panel. */
@media (prefers-reduced-motion: reduce) {
  .scrolly__media { position: relative; height: 60vh; }
  .scrolly__panels { margin-top: 0; }
  .scrolly__panel, .scrolly__panel:first-child { min-height: 0; padding-block: var(--sp-6); }
  .scrolly__panel > .wrap { opacity: 1; transform: none; }
  .scrolly__media > img { transform: none; }
}
html:not(.js-reveal) .scrolly__panel > .wrap { opacity: 1; transform: none; }
/* Scroll-linked panels.
   The class-based version above flips at a threshold, so panels snap rather
   than cross-fade. Where the browser supports scroll-driven animations the
   panel is tied to its own position in the viewport instead: the fade tracks
   the scroll continuously and runs on the compositor, off the main thread.
   Everything else keeps the observer fallback. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .scrolly__panel > .wrap {
      opacity: 1;
      transform: none;
      transition: none;
      animation: panel-track linear both;
      animation-timeline: view();
      animation-range: entry 10% exit 90%;
    }
    @keyframes panel-track {
      0%        { opacity: 0; transform: translateY(30px); }
      28%, 72%  { opacity: 1; transform: none; }
      100%      { opacity: 0; transform: translateY(-30px); }
    }
  }
}
/* --- Table of contents ---------------------------------------------------- */
/* minmax(0, 1fr), not the implicit `auto` track this had.
   A grid item's automatic minimum size is its min-content, so an auto track
   never shrinks below the widest thing inside it — and on one page that was a
   994px column inside a 335px phone, dragging twenty pages sideways. The
   images were only the visible half of it: capping them at 100% left them
   filling a container that was itself too wide. A track that can reach zero is
   what actually holds the page together; the 1024px rules below then take over
   and add the contents rail. */
.layout-aside { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-7); align-items: start; }
@media (min-width: 1024px) {
  .layout-aside { grid-template-columns: minmax(0, 1fr) 16rem; }
  /* 289 of the 299 pages using this layout render no contents rail at all, and
     were still reserving its column: a 16rem hole down the right of nearly
     every page on the site. With nothing to put there, the reading column
     keeps exactly the width it had and centres instead, so the line length
     does not change and the page stops looking off-balance. */
  /* 289 of the 299 pages using this layout render no contents rail and were
     still reserving its 16rem column. The column goes, but the text stays
     left-aligned where it started: centring it only trades one gutter for two
     and pushes the reading column away from the title above it.
     Instead the measure grows a little, so the text uses more of the width it
     just got back. 66ch is the comfortable ceiling for a rail page; 76ch is
     still inside what is readable and leaves noticeably less empty. */
  .layout-aside--solo { grid-template-columns: minmax(0, 1fr); }
  .layout-aside--solo .prose > * { max-width: 76ch; }
}
/* A sticky element taller than the viewport pins its top and hangs the rest
   below the fold, where it can never be reached: on a page with sixty-five
   headings that hides most of the list and leaves the marker tracking entries
   the reader cannot see. Capping the height and letting the list scroll keeps
   the whole rail usable. */
.toc {
  position: sticky; top: calc(var(--header-h) + 1.5rem);
  font-size: var(--step--1);
  display: flex; flex-direction: column;
  max-height: calc(100dvh - var(--header-h) - 3rem);
}
/* Only the list scrolls, so the heading stays put. overscroll-behavior stops
   the page from taking over once the rail reaches its end. */
/* Scrollable, but with no scrollbar drawn: the rail follows the reader down
   the page on its own, so a bar to drag is furniture nobody needs and it
   crowds an already narrow column. */
.toc ol {
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;          /* Firefox */
  -ms-overflow-style: none;       /* old Edge */
}
.toc ol::-webkit-scrollbar { width: 0; height: 0; }
.toc h2 { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-faint); margin-bottom: var(--sp-3); }
.toc ol { position: relative; list-style: none; padding: 0; margin: 0; border-left: 2px solid var(--border); }
.toc li { margin: 0; }
.toc a {
  display: block; padding: var(--sp-2) var(--sp-3);
  color: var(--text-muted); text-decoration: none;
  transition: color var(--dur-2) var(--ease);
}
/* Everything currently on screen is lit, not just one entry: on a page laid
   out as a grid, three people are in front of the reader at once. */
.toc a:hover, .toc a.is-reading { color: var(--accent); }
.toc a.is-reading { font-weight: 600; }
/* One marker for the whole list rather than a border on each item. Reading
   moves continuously down the page, so the indicator travels with it instead
   of blinking out in one place and in again in another. It is a 1px bar scaled
   to the height of the current item, so both the move and the resize are pure
   transform and stay off the main thread. */
.toc__marker {
  position: absolute; left: -2px; top: 0;
  width: 2px; height: 1px;
  background: var(--accent);
  transform-origin: top;
  transform: translateY(0) scaleY(0);
  opacity: 0;
  transition:
    transform var(--dur-3) var(--ease-out),
    opacity var(--dur-2) var(--ease);
}
/* The first placement is where reading already is, not somewhere it travelled
   from, so it appears rather than slides. */
.toc__marker[data-init="false"] { transition: none; }
@media (prefers-reduced-motion: reduce) {
  .toc__marker { transition: opacity var(--dur-2) var(--ease); }
}
.toc .is-sub a { padding-left: var(--sp-5); font-size: 0.85rem; }
@media (max-width: 1023px) { .toc { display: none; } }
/* --- Pagination + prev/next ---------------------------------------------- */
.pagination { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; align-items: center; margin-top: var(--sp-7); }
.pagination a, .pagination span {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.75rem; min-height: 2.75rem; padding: var(--sp-2) var(--sp-3); text-align: center;
  border: 1px solid var(--border); border-radius: var(--radius);
  text-decoration: none; color: var(--text); font-variant-numeric: tabular-nums;
}
.pagination a:hover { border-color: var(--accent); color: var(--accent); }
.pagination [aria-current="page"] { background: var(--magenta-600); border-color: var(--magenta-600); color: var(--white); font-weight: 700; }
.pagination .is-gap { border: 0; }
.prevnext { display: grid; gap: var(--sp-4); margin-top: var(--sp-8); padding-top: var(--sp-6); border-top: 1px solid var(--border); }
@media (min-width: 700px) { .prevnext { grid-template-columns: 1fr 1fr; } }
.prevnext a { display: block; padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius); text-decoration: none; color: var(--text); }
.prevnext a:hover { border-color: var(--accent); }
.prevnext span { display: block; font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.1em; color: var(--text-faint); margin-bottom: var(--sp-2); }
.prevnext .is-next { text-align: right; }
/* --- Filter bar ----------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-6); }
.filters a {
  display: inline-flex; align-items: center; min-height: 2.375rem;
  padding: 0.35em 0.9em; border: 1px solid var(--border); border-radius: 100px;
  font-size: 0.875rem; text-decoration: none; color: var(--text-muted);
  white-space: nowrap;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}
.filterbar { margin-bottom: var(--sp-6); }
.filterbar .filters { margin-bottom: 0; }
.filters--rest {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
/* The extra categories used to appear instantly and shove the grid down. The
   panel wipes open from the bar it belongs to instead: clip-path and opacity
   are both composited, so the list below still reflows but nothing paints
   twice for the sake of it. */
.filters--rest[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .filters--rest:not([hidden]) {
    animation: filters-open var(--dur-3) var(--ease-out) both;
  }
  @keyframes filters-open {
    from { opacity: 0; clip-path: inset(0 0 100% 0); }
    to   { opacity: 1; clip-path: inset(0 0 0 0); }
  }
}
/* The disclosure is a pill on the same row, so the bar reads as one control. */
.filters__toggle {
  display: inline-flex; align-items: center; gap: 0.45em;
  min-height: 2.375rem; padding: 0.35em 0.9em;
  border: 1px dashed var(--border-strong); border-radius: 100px;
  background: transparent; color: var(--text-muted);
  font-size: 0.875rem; font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: border-color var(--dur-2) var(--ease), color var(--dur-2) var(--ease);
}
.filters__toggle span {
  width: 0.5rem; height: 0.5rem; flex: 0 0 auto;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform var(--dur-2) var(--ease);
}
.filters__toggle[aria-expanded="true"] span { transform: rotate(-135deg) translate(-1px, -1px); }
.filters__toggle:hover { border-color: var(--accent); color: var(--accent); }
.filters__toggle:active { transform: scale(0.97); }
.filters a:hover { border-color: var(--accent); color: var(--accent); }
.filters a[aria-current="page"] { background: var(--magenta-600); border-color: var(--magenta-600); color: var(--white); font-weight: 600; }
/* --- Search --------------------------------------------------------------- */
.search-dialog {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: start center;
  padding: var(--sp-5);
  background: rgb(28 3 16 / 0.6);
  backdrop-filter: blur(3px);
  opacity: 1; visibility: visible;
  transition: opacity var(--dur-2) var(--ease), visibility 0s;
}
.search-dialog[hidden] {
  display: grid;
  visibility: hidden;
  opacity: 0;
  transition:
    opacity var(--dur-2) var(--ease),
    visibility 0s linear var(--dur-2);
}
.search-dialog[hidden] .search-panel {
  transform: scale(0.97) translateY(-8px);
}
.search-panel {
  width: min(100%, 40rem); margin-top: 8vh; background: var(--bg-raised);
  transform: none;
  transition: transform var(--dur-2) var(--ease-out);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow: hidden;
}
.search-panel__top { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border-bottom: 1px solid var(--border); }
.search-panel input[type="search"] {
  flex: 1; border: 0; background: transparent; font-size: var(--step-1); padding: var(--sp-2);
}
.search-panel input[type="search"]:focus { outline: none; }
.search-results { max-height: min(60vh, 32rem); overflow-y: auto; padding: var(--sp-2); }
.search-results li { list-style: none; }
/* A grid, not three inline spans. Inline, the kind ran straight into the title
   with nothing between them — "ARTICLEI'm a 51 year old NHS nurse" — and the
   snippet ran into the title the same way. Each part gets its own row. */
.search-results a {
  display: grid; gap: 0.3rem;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius);
  text-decoration: none; color: var(--text);
}
.search-results a:hover, .search-results a:focus-visible { background: var(--surface-tint); }
.search-results .r-title { font-weight: 600; line-height: 1.3; }
/* The kind is a label, so it looks like one: a pill that sizes to its word and
   stops, rather than a run of small capitals the eye reads as the start of the
   headline. */
.search-results .r-kind {
  justify-self: start;
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.09em; font-weight: 700;
  color: var(--text-muted);
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.16rem 0.5rem;
  line-height: 1.45;
}
.search-results a:hover .r-kind, .search-results a:focus-visible .r-kind {
  border-color: var(--accent); color: var(--accent);
}
.search-results .r-snip { font-size: var(--step--1); color: var(--text-muted); line-height: 1.5; }
.search-results mark { background: var(--pink-100); color: var(--plum-900); padding: 0 2px; border-radius: 2px; }
:root[data-theme="dark"] .search-results mark { background: var(--plum-700); color: var(--white); }
.search-empty { padding: var(--sp-6); text-align: center; color: var(--text-faint); }
/* --- Fixed social rail ----------------------------------------------------
   Pinned to the right edge, as the original theme had. The label slides out on
   hover and focus; the link's accessible name comes from that same label, so
   nothing is announced twice. */
.social-rail {
  position: fixed;
  top: 50%;
  /* Sat further in than it needs to. Overlapping the page is fine and often
     looks better; what matters is that it never lands on text, and the wrap
     reserves its width for that. */
  right: clamp(1.25rem, 2.4vw, 2.75rem);
  transform: translateY(-50%);
  z-index: 90;
}
.social-rail ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.social-rail a {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  text-decoration: none;
  /* Measured, not chosen: 4.66:1 on white and 3.96:1 on the dark plum. White
     would vanish over the prose and the deeper brand pinks vanish over a
     photograph; this is the one point on the ramp that clears both. */
  color: #c9407b;
}
.social-rail__icon {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  flex: 0 0 auto;
  border-radius: 50%;
  /* No disc. The artwork has no ground of its own, so whatever the page is
     doing behind the rail is what the marks sit on: white where the prose is
     white, the photograph where a photograph is. That was the whole point and
     I had been painting a plum circle over it.

     Which leaves the edge and the glyph to hold on both. The ring is drawn
     twice, light inside and dark outside, so one half of it always registers.
     The glyph is #c9407b, measured at 4.66:1 on white and 3.96:1 on the dark
     plum: the only part of the brand ramp that clears 3:1 on both. */
  background: transparent;
  /* The two rings are split so that hovering does not repaint a shadow. The
     dark outer ring is static: it defines the edge on white and on a photograph
     alike, and it still reads against the magenta hover fill. Only the light
     inner ring has to go, and it lives on ::after so losing it is an opacity
     fade. It cannot join the outer ring there — the circle clips its own
     overflow to hold the artwork, so an outer shadow on a child is cut off. */
  box-shadow: 0 0 0 1px rgb(43 5 25 / 0.30);
  transition:
    background-color var(--dur-2) var(--ease),
    transform var(--dur-2) var(--ease);
}
.social-rail__icon::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.55);
  transition: opacity var(--dur-2) var(--ease);
  pointer-events: none;
}
.social-rail svg {
  width: 1.05rem; height: 1.05rem; fill: currentColor;
  /* A ring of page colour immediately around the glyph, so the mark separates
     from the artwork behind it without needing a solid disc. */
  filter:
    drop-shadow(0 0 1.5px rgb(255 255 255 / 0.85))
    drop-shadow(0 0 3px rgb(255 255 255 / 0.6));
  position: relative; z-index: 1;
}
:root[data-theme="dark"] .social-rail svg,
.hero .social-rail svg {
  filter: drop-shadow(0 0 1.5px rgb(28 3 16 / 0.8)) drop-shadow(0 0 3px rgb(28 3 16 / 0.55));
}
.social-rail__label {
  position: absolute;
  right: calc(100% + 0.5rem);
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0.45em 0.8em;
  border-radius: var(--radius);
  background: var(--plum-900);
  color: var(--white);
  opacity: 0;
  transform: translateX(0.5rem);
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.social-rail a:hover .social-rail__icon,
.social-rail a:focus-visible .social-rail__icon {
  background: var(--magenta-600);
  transform: translateX(-2px);
}
.social-rail a:hover .social-rail__icon::after,
.social-rail a:focus-visible .social-rail__icon::after { opacity: 0; }
.social-rail a:hover .social-rail__label,
.social-rail a:focus-visible .social-rail__label {
  opacity: 1;
  transform: translateX(0);
}
.social-rail a:focus-visible { outline: none; }
.social-rail a:focus-visible .social-rail__icon { outline: 2px solid var(--pink-300); outline-offset: 3px; }
/* The rail needs a page gutter of at least 84px (24 offset + 44 icon + 16
   breathing room). With a 1180px content column that means a 1348px viewport;
   below it the rail sits on top of the sidebar, so it hides and the footer
   icons carry the same links. */
/* Between 1150 and 1360 the page gutter is too narrow for a 44px rail plus its
   slide-out label, but not too narrow for the rail itself. Shrink rather than
   hide: smaller marks, tighter to the edge, and no label — the label is what
   would reach into the content. */
@media (max-width: 1360px) {
  .social-rail { right: 0.9rem; }
  .social-rail ul { gap: 0.35rem; }
  .social-rail__icon { width: 2.125rem; height: 2.125rem; }
  .social-rail svg { width: 0.85rem; height: 0.85rem; }
  .social-rail__label { display: none; }
}
/* At 1280 the content column stops growing and the gutter is 50px — the
   shrunken rail needs 46px, so this is exactly where it stops fitting. Below
   it the footer icons carry the same links. */
/* Stays vertical all the way down: laid out as a column it reads as part of
   the page's furniture, where a horizontal cluster in the corner reads as a
   widget bolted on. Below 1280 the page gutter is only 20-30px, so the marks
   shrink and tuck against the edge rather than being dropped. */
@media (max-width: 1279px) {
  .social-rail { right: 0.9rem; }
  .social-rail ul { gap: 0.3rem; }
  .social-rail__icon { width: 1.9rem; height: 1.9rem; }
  .social-rail svg { width: 0.8rem; height: 0.8rem; }
}
/* On a phone there is no gutter at all and the footer carries the same links
   a short scroll away. */
@media (max-width: 47rem) { .social-rail { display: none; } }
@media print { .social-rail { display: none; } }
/* --- Footer --------------------------------------------------------------- */
.site-footer { margin-top: auto; background: var(--plum-900); color: #efdfe7; padding-block: var(--sp-8) var(--sp-6); }
.site-footer a { color: #efdfe7; text-decoration: none; }
.site-footer a:hover { color: var(--pink-300); text-decoration: underline; }
.site-footer h2 { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.14em; color: var(--pink-300); margin-bottom: var(--sp-4); }
/* Five blocks: the brand and four link columns. auto-fit fitted four of them
   at this width and dropped the fifth onto a row of its own, leaving three
   empty cells beside it. Five never divides into four, so the layout is stated
   rather than inferred, and every step below has a whole number of rows. */
.footer__grid { display: grid; gap: var(--sp-5) var(--sp-6); grid-template-columns: 1fr; }
/* Brand across the top, then the four link columns as a tidy two by two. */
@media (min-width: 40rem) {
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
}
/* Everything on one line, the brand given a little more room for its sentence. */
@media (min-width: 64rem) {
  .footer__grid { grid-template-columns: 1.3fr repeat(4, minmax(0, 1fr)); }
  .footer__brand { grid-column: auto; }
}
.footer__links { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-1); font-size: 0.95rem; }
.footer__links a { display: inline-block; padding-block: 0.45rem; }
.footer__brand { max-width: 24rem; }
.footer__brand p { color: #d3b7c6; font-size: 0.95rem; margin-top: var(--sp-3); }
/* Social row. Circular rather than boxed: at this size a hairline circle reads
   as a considered mark, where a rounded square reads as a button that lost its
   label. The fill only appears on hover, so the row stays quiet by default. */
.social {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: 0;
}
.social li { margin: 0; }
.social a {
  --social-size: 2.5rem;
  position: relative;
  display: grid;
  place-items: center;
  width: var(--social-size);
  height: var(--social-size);
  padding: 0;
  border-radius: 50%;
  color: #f0dbe6;
  background: rgb(255 255 255 / 0.05);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.16);
  text-decoration: none;
  transition:
    color var(--dur-2) var(--ease),
    background-color var(--dur-2) var(--ease),
    transform var(--dur-2) var(--ease);
}
/* The hover ring and glow sit on ::after and arrive by fading in. Transitioning
   box-shadow on the anchor itself repainted a 2.5rem circle on every hover, and
   a shadow is the one thing on the banned list that looks free until you watch
   a paint profile. Same appearance, composited. */
.social a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px var(--pink-300), 0 6px 16px rgb(255 111 181 / 0.28);
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease);
  pointer-events: none;
}
.social a:hover {
  color: var(--plum-900);
  background: var(--pink-300);
  transform: translateY(-2px);
  text-decoration: none;
}
.social a:hover::after { opacity: 1; }
.social a:active { transform: translateY(0); }
.social a:focus-visible {
  outline: 2px solid var(--pink-300);
  outline-offset: 3px;
}
/* Optical sizing: these glyphs have different natural weights, so the box is
   fixed and the mark is centred within it rather than scaled to fill. */
.social svg {
  width: 1.05rem;
  height: 1.05rem;
  fill: currentColor;
  transition: transform var(--dur-2) var(--ease);
}
/* The tap target stays 44px even though the visible circle is 40px. */
.social a::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
}
@media (prefers-reduced-motion: reduce) {
  .social a, .social svg { transition: none; }
  .social a:hover { transform: none; }
  .social a:hover svg { transform: none; }
}
.footer__legal {
  margin-top: var(--sp-7); padding-top: var(--sp-5); border-top: 1px solid rgb(255 255 255 / 0.15);
  display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: space-between;
  font-size: var(--step--1); color: #c9a6b8;
}
/* --- Callout / CTA band --------------------------------------------------- */
.cta-band {
  background: linear-gradient(100deg, var(--plum-800), var(--magenta-600));
  color: var(--white); border-radius: var(--radius-lg);
  padding: var(--sp-7); display: grid; gap: var(--sp-5); align-items: center;
}
@media (min-width: 800px) { .cta-band { grid-template-columns: 1fr auto; } }
.cta-band h2 { color: var(--white); font-size: var(--step-3); }
.cta-band p { color: #f3dfe9; margin-top: var(--sp-3); max-width: 52ch; }
.cta-band .btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
/* --- Portrait grid (Darker Side of Pink) --------------------------------- */
.portraits { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(min(100%, 11rem), 1fr)); list-style: none; padding: 0; }
.portrait { position: relative; border-radius: var(--radius); overflow: hidden; background: var(--plum-800); }
.portrait img { width: 100%; aspect-ratio: 3/4; object-fit: cover; transition: transform var(--dur-3) var(--ease); }
.portrait:focus-within img { transform: scale(1.04); }
.portrait__name {
  position: absolute; inset-inline: 0; bottom: 0; padding: var(--sp-4) var(--sp-3) var(--sp-3);
  background: linear-gradient(transparent, rgb(28 3 16 / 0.92));
  color: var(--white); font-family: var(--font-display); font-weight: 700; font-size: 0.95rem;
}
.portrait a { position: absolute; inset: 0; }
.portrait a span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
/* --- Hover movement, pointer devices only ---------------------------------
   A touch tap fires :hover, and on mobile the state then sticks until the next
   tap elsewhere — so a card lifts and stays lifted. Colour changes above are
   left ungated because they read as useful tap feedback; movement is not. */
@media (hover: hover) and (pointer: fine) {
  .card:hover { transform: translateY(-4px); }
  .card:hover .card__media img { transform: scale(1.04); }
  .linklist a:hover { transform: translateX(4px); }
  .linklist a:active { transform: translateX(4px) scale(0.99); }
  .montage li:hover img { transform: scale(1.05); }
  .portrait:hover img { transform: scale(1.04); }
  .prose a:hover > img { transform: scale(1.02); }
  .social a:hover svg { transform: scale(1.06); }
}
/* --- Print ---------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .toc, .prevnext, .pagination, .search-dialog, .drawer { display: none !important; }
  body { color: #000; background: #fff; }
  a { text-decoration: underline; }
  .prose a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}
/* --- Team member blocks ---------------------------------------------------
   Used for the trustees page and for "Our friends not forgotten", the memorial
   page. The plugin's own stylesheet did not migrate, so the three-column
   layout it was written for collapsed into a single very long column. The
   markup is intact; this gives it the grid back.

   The row wrappers become `display: contents` so every member joins one grid
   and the columns stay level, instead of each row of three sizing itself. */
/* The grid fills its column. The measure exists to keep running text readable;
   a grid of cards is not running text. */
.prose > .tmm, .tmm { max-width: none; }
/* Masonry, not grid. These biographies run from one line to thirty, and grid
   stretches every cell in a row to match the tallest, so a short entry beside a
   long one became a card that was mostly empty space. Columns let each card
   end where its content ends. */
.tmm_wrap {
  columns: 3 17rem;
  column-gap: var(--sp-5);
  margin: var(--sp-6) 0;
  max-width: none;
}
.tmm_container { display: contents; }
/* Once the script has distributed the cards by measured height, the wrapper
   becomes a plain grid of flex columns and the CSS column fallback stands
   down. */
.tmm_wrap.is-masonry {
  columns: auto;
  display: grid;
  grid-template-columns: repeat(var(--masonry-cols, 3), minmax(0, 1fr));
  gap: 0 var(--sp-5);
  align-items: start;
}
.tmm_col { display: flex; flex-direction: column; min-width: 0; }
.tmm_member {
  break-inside: avoid;
  margin: 0 0 var(--sp-5);
  padding: var(--sp-5) var(--sp-5) var(--sp-6);
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.tmm_textblock { display: flex; flex-direction: column; gap: var(--sp-1); }
.tmm_names {
  font-family: var(--font-display);
  font-size: 1.15rem; font-weight: 700; line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text);
}
.tmm_job {
  font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent);
}
/* A hairline separates who someone was from the account of their illness.
   Without it the name runs straight into a list of drug names. */
.tmm_desc {
  margin-top: var(--sp-1);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
  font-size: 0.9rem; line-height: 1.65; color: var(--text-muted);
}
.tmm_desc > p { margin: 0 0 var(--sp-3); }
.tmm_desc > p:last-child { margin-bottom: 0; }
/* The date is the reason the page exists, so it is set in the body colour and
   carries the brand's own mark. It is not always the last line: several
   entries note how treatment was funded afterwards. */
.tmm_died {
  display: flex; align-items: baseline; gap: 0.5em;
  font-weight: 600; color: var(--text); font-size: 0.9rem;
}
.tmm_died::before {
  content: ""; flex: none;
  width: 0.5rem; height: 0.5rem; border-radius: 50%;
  background: var(--accent);
  transform: translateY(-0.1em);
}
.tmm_scblock { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.tmm_scblock a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem;
  border: 1px solid var(--border); border-radius: 50%;
  color: var(--text-muted); background: var(--bg);
  transition: color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease);
}
.tmm_scblock svg { width: 0.95rem; height: 0.95rem; fill: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .tmm_scblock a:hover { color: var(--accent); border-color: var(--accent); }
}
.tmm_scblock a:active { transform: scale(0.94); }
@media (prefers-reduced-motion: reduce) {
  .tmm_scblock a { transition: none; }
  .tmm_scblock a:active { transform: none; }
}
/* --- Ribbon pointer -------------------------------------------------------
   The METUPUK ribbon: one path, proportioned off the logo, fading pink to
   near-black down its length. Two deliberate limits: it applies only where a
   real mouse drives a real cursor, and every interactive control keeps the
   standard hand, so nothing about what is clickable is hidden behind
   decoration. */
@media (hover: hover) and (pointer: fine) {
  body { cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22a%22%20gradientUnits%3D%22userSpaceOnUse%22%20x1%3D%220%22%20y1%3D%222%22%20x2%3D%220%22%20y2%3D%2220.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23f6bdd0%22%2F%3E%3Cstop%20offset%3D%22.25%22%20stop-color%3D%22%23f26c9b%22%2F%3E%3Cstop%20offset%3D%22.45%22%20stop-color%3D%22%23ee6b9a%22%2F%3E%3Cstop%20offset%3D%22.62%22%20stop-color%3D%22%23a04a6a%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%232e2a2b%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23232021%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23ffffff%22%20stroke-width%3D%223.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22url%28%23a%29%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E") 10 2, auto; }
  a, button, summary, label, select, [role="button"], [tabindex]:not([tabindex="-1"]) { cursor: pointer; }
  input, textarea { cursor: text; }
  :root[data-theme="dark"] body { cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22b%22%20gradientUnits%3D%22userSpaceOnUse%22%20x1%3D%220%22%20y1%3D%222%22%20x2%3D%220%22%20y2%3D%2220.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23fbd8e6%22%2F%3E%3Cstop%20offset%3D%22.25%22%20stop-color%3D%22%23f6a8c8%22%2F%3E%3Cstop%20offset%3D%22.45%22%20stop-color%3D%22%23f18bb4%22%2F%3E%3Cstop%20offset%3D%22.62%22%20stop-color%3D%22%23dd5c92%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%23b03a6c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23932f59%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%231b0d12%22%20stroke-width%3D%223.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22url%28%23b%29%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E") 10 2, auto; }
}
@media (hover: hover) and (pointer: fine) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body { cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22b%22%20gradientUnits%3D%22userSpaceOnUse%22%20x1%3D%220%22%20y1%3D%222%22%20x2%3D%220%22%20y2%3D%2220.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23fbd8e6%22%2F%3E%3Cstop%20offset%3D%22.25%22%20stop-color%3D%22%23f6a8c8%22%2F%3E%3Cstop%20offset%3D%22.45%22%20stop-color%3D%22%23f18bb4%22%2F%3E%3Cstop%20offset%3D%22.62%22%20stop-color%3D%22%23dd5c92%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%23b03a6c%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23932f59%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%231b0d12%22%20stroke-width%3D%223.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012.0%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202.0%2012.3%202.0%20C10.5%202.0%209.1%203.5%209.0%205.6%20C8.9%208.4%2010.7%2010.7%2012.0%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22url%28%23b%29%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E") 10 2, auto; }
}

/* --- Reading progress -----------------------------------------------------
   A hairline under the header showing how far through a long page you are.
   Scaled from the left on a composited transform, so it costs nothing to
   animate, and it is decoration for the eye only: the scrollbar already
   carries this information for anyone who needs it announced. */
.read-progress {
  position: fixed; top: var(--header-h); left: 0; right: 0;
  /* Under the header (100), not over it. The bar sits exactly at the header's
     lower edge so nothing is hidden by dropping it, but above the header a
     dropdown panel is a child of the header's stacking context — at 120 the
     hairline drew a pink line straight across the open menu. */
  height: 2px; z-index: 95;
  background: linear-gradient(90deg, var(--magenta-600), var(--pink-400));
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease);
}
@media (prefers-reduced-motion: reduce) { .read-progress { transition: none; } }
@media print { .read-progress { display: none; } }

/* --- Artwork behind the social marks --------------------------------------
   Not a repeated logo: a strip built from the things the charity actually
   says. Ribbons, the number 31, their campaign hashtags set sideways, and a
   scatter of small marks -- one for each woman, which is the whole argument of
   the site in its plainest form. The icons stop being flat discs and become windows. Behind them sits a tall
   strip of ribbons in the brand's darker range, and the strip travels as the
   page scrolls, so a different part of it shows through each mark the further
   down you go. Nobody has to notice it; it rewards the person who does.

   The artwork is kept deliberately dark so the white glyph on top stays
   legible wherever the strip happens to be. */
@media (prefers-reduced-motion: reduce) {
  /* Still artwork, just not travelling. */
  .social-rail__icon { background-position: center 0; }
}

/* --- Press feedback on touch-first controls -------------------------------
   Hover states do not exist on a phone, so on these the press is the only
   acknowledgement the interface gives. Kept at the fast end of the budget:
   these are navigation, not moments. */
.drawer__list a:active,
.pagination a:active,
.c-disclosure > summary:active,
.card:active {
  transform: scale(0.985);
}
.drawer__list a, .pagination a, .c-disclosure > summary {
  transition: transform var(--dur-1) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .drawer__list a:active,
  .pagination a:active,
  .c-disclosure > summary:active,
  .card:active { transform: none; }
}

/* --- Small images in flowing text -----------------------------------------
   A 271px portrait sitting alone in an 868px column leaves two thirds of the
   line empty and stops the reading dead. Anything narrow enough to leave a
   readable column beside it is set into the text instead, the way a magazine
   would. The threshold is deliberate: the text beside it must still get about
   55 characters, so this only applies from 1100px up, and only to images that
   are genuinely small. */
@media (min-width: 1100px) {
  .prose > p.prose-float {
    float: left;
    width: min(42%, 20rem);
    margin: 0.35rem var(--sp-5) var(--sp-4) 0;
  }
  .prose > p.prose-float + * { margin-top: 0; }
  /* Nothing structural is allowed to wrap around it. */
  .prose > h2, .prose > h3, .prose > .c-embed,
  .prose > .prose-grid, .prose > blockquote { clear: both; }
}
.prose > p.prose-float img { width: 100%; height: auto; }

/* Pictures are wider than the paragraphs. Text stays at its measure because
   that is what makes it readable; an image has no such limit, and holding both
   to the same width was what made these pages feel like a column of grey with
   occasional grey rectangles in it. Letting the image break past the measure
   to the full width of its column gives the page a rhythm, and costs nothing:
   only images with a source large enough to cover that width are marked, so
   none of them softens.

   The break is one-sided. The image keeps the text's left edge and grows to
   the right, so the reading margin never moves. */
.prose > .prose-fill,
.prose > img.prose-fill,
.prose > a.prose-fill {
  max-width: none;
  width: 100%;
  margin-top: var(--sp-6);
  margin-bottom: var(--sp-6);
}
.prose > .prose-fill img,
.prose > img.prose-fill,
.prose > a.prose-fill img { display: block; width: 100%; height: auto; }
.prose > .prose-fill + * { margin-top: var(--sp-6); }

/* --- Acts -----------------------------------------------------------------
   Long articles are grouped into acts, and every other one sits on a tinted
   ground. The reading measure never changes; what changes is the surface under
   it, which is what makes a long page feel like something you move through
   rather than one column that goes on.

   The tint reaches the edges of the window without leaving the grid: a very
   large spread shadow paints outward, and clip-path stops it bleeding
   vertically into the acts above and below. */
/* The break between acts used to total about 130px — sp-6 below plus sp-8
   above. Against a 16px paragraph gap that is eight times the spacing, and
   where an act opened on a paragraph rather than a heading it read as a hole
   in the middle of a continuous argument rather than as a section break.
   60px is under four times the paragraph gap: unmistakably a break, with the
   lead-paragraph styling below doing the rest of the work. */
.act { padding-block: var(--sp-5); }
.act + .act { padding-top: var(--sp-6); }
.act__inner > * { max-width: min(var(--measure), 100%); }
.act__inner > * + * { margin-top: var(--sp-4); }
/* No coloured bands. Blocks of tint were a blunt way to say "you have moved",
   and they made the page look like a stack of boxes. The movement itself says
   it: each act rises into place as it comes into view, so the page arrives
   under the reader instead of sitting there waiting.

   The act settles before it is reached, never while it is being read. That is
   the whole difference between this and text that animates at you. */
.js-reveal .act[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  /* Same gesture as every other reveal, so the same duration. */
  transition:
    opacity var(--dur-4) var(--ease-out),
    transform var(--dur-4) var(--ease-out);
}
.js-reveal .act[data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js-reveal .act[data-reveal] { opacity: 1; transform: none; transition: none; }
}
/* The opening line of an act carries it, so the act announces itself without
   a heading anyone had to write for it. */
.act__inner > p:first-of-type {
  font-family: var(--font-display); font-weight: 600;
  font-size: var(--step-1); line-height: 1.42; letter-spacing: -0.01em;
  color: var(--text); max-width: 46ch;
}
/* The first act opens the page, so it does not need the extra air above it. */
.prose > .act:first-child { padding-top: 0; }

/* An image opening a paragraph of prose sits above the sentence, not in it. */
.prose p.has-lead-image > a:first-child,
.prose p.has-lead-image > img:first-child {
  display: block;
  margin-bottom: var(--sp-3);
}

/* --- Story cards ----------------------------------------------------------
   A page that is a collection of people's stories rather than one piece of
   prose. Laid out as a grid it reads as what it is, and stops being thirty
   screens of scrolling. */
.story-grid {
  display: grid;
  gap: var(--sp-6);
  grid-template-columns: 1fr;
  margin: var(--sp-6) 0;
  max-width: none;
}
@media (min-width: 40rem) { .story-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 75rem) { .story-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.story { display: flex; flex-direction: column; min-width: 0; }
.story__media {
  border-radius: var(--radius); overflow: hidden;
  background: var(--bg-sunken); margin-bottom: var(--sp-4);
}
/* One shape for every card, whatever shape the photograph arrived in. */
.story__media img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.story__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: var(--step-0); line-height: 1.3; color: var(--text);
  max-width: none; margin: 0;
}
.story__body {
  font-size: 0.94rem; line-height: 1.6; color: var(--text-muted);
  max-width: none; margin-top: var(--sp-3);
}
.story__media a { display: block; }

/* Short images keep square corners: a 10px radius on a 38px-tall logo curves
   away a quarter of it, and the clip took the last letter off a wordmark. */
.prose .img--flat,
.prose a.img--flat { border-radius: 0; overflow: visible; }

/* --- The strip behind the marks -------------------------------------------
   On its own layer, moved with a transform. It used to be a background-position
   written to four icons on every scrolled frame, which cannot be composited:
   four repaints of a 19KB SVG per frame for the whole length of every scroll.
   A transform on a pseudo-element costs the compositor nothing.

   The layer is taller than the circle at both ends so there is always strip to
   show, and the circle clips it. */
.social-rail__icon { position: relative; overflow: hidden; isolation: isolate; }
.social-rail__icon::before {
  content: "";
  position: absolute;
  /* Deep enough that a wrapped offset always has strip above and below it.
     background-position wrapped inside an endlessly repeating tile; a
     transform moves a real box, so the box has to be bigger than the travel. */
  left: 0; right: 0; top: -1400px; bottom: -1400px;
  z-index: -1;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2272%22%20height%3D%221900%22%20viewBox%3D%220%200%2072%201900%22%3E%3Ccircle%20cx%3D%2265%22%20cy%3D%221398%22%20r%3D%221.3%22%20fill%3D%22%23c9548c%22%20opacity%3D%220.23%22%2F%3E%3Cg%20transform%3D%22translate%2835.9%201059.3%29%20rotate%28-28%2012%2012%29%20scale%281.51%29%22%20opacity%3D%220.38%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%237a1846%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate%28-14.6%20847.7%29%20rotate%2856%2012%2012%29%20scale%281.47%29%22%20opacity%3D%220.31%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%237a1846%22%20stroke-width%3D%223.2%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate%28-7.3%20495.7%29%20rotate%2816%2012%2012%29%20scale%282.32%29%22%20opacity%3D%220.36%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23c9548c%22%20stroke-width%3D%222.0%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate%288.7%201559.3%29%20rotate%2857%2012%2012%29%20scale%281.75%29%22%20opacity%3D%220.28%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%2393245a%22%20stroke-width%3D%222.0%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2279%22%20y%3D%221423%22%20transform%3D%22rotate%28-88%2079%201423%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%228.8%22%20fill%3D%22%23b03a6e%22%20opacity%3D%220.35%22%3E%23IAmThe31%3C%2Ftext%3E%3Ccircle%20cx%3D%2225%22%20cy%3D%22942%22%20r%3D%222.2%22%20fill%3D%22%2393245a%22%20opacity%3D%220.22%22%2F%3E%3Ctext%20x%3D%22-18%22%20y%3D%22980%22%20transform%3D%22rotate%28-86%20-18%20980%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%228.9%22%20fill%3D%22%238e1f52%22%20opacity%3D%220.37%22%3E31%20a%20day%3C%2Ftext%3E%3Cg%20transform%3D%22translate%2832.0%20977.0%29%20rotate%28-62%2012%2012%29%20scale%281.80%29%22%20opacity%3D%220.39%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23d2649a%22%20stroke-width%3D%223.6%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2240%22%20y%3D%228%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2230%22%20fill%3D%22%238e1f52%22%20opacity%3D%220.19%22%3E31%3C%2Ftext%3E%3Cg%20transform%3D%22translate%2855.7%201113.2%29%20rotate%2834%2012%2012%29%20scale%282.28%29%22%20opacity%3D%220.38%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23f0a8ca%22%20stroke-width%3D%222.7%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2245%22%20y%3D%221149%22%20transform%3D%22rotate%28-88%2045%201149%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%2210.1%22%20fill%3D%22%238e1f52%22%20opacity%3D%220.23%22%3Eincurable%3C%2Ftext%3E%3Cg%20transform%3D%22translate%28-16.0%20744.6%29%20rotate%28-51%2012%2012%29%20scale%281.28%29%22%20opacity%3D%220.31%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23f0a8ca%22%20stroke-width%3D%222.7%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Cg%20transform%3D%22translate%2824.1%201608.7%29%20rotate%28-61%2012%2012%29%20scale%282.05%29%22%20opacity%3D%220.38%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23d2649a%22%20stroke-width%3D%222.2%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2217%22%20y%3D%22628%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2237%22%20fill%3D%22%23f0a8ca%22%20opacity%3D%220.25%22%3E31%3C%2Ftext%3E%3Ctext%20x%3D%226%22%20y%3D%22785%22%20transform%3D%22rotate%28-90%206%20785%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%2210.8%22%20fill%3D%22%23b03a6e%22%20opacity%3D%220.34%22%3E%23IAmThe31%3C%2Ftext%3E%3Ccircle%20cx%3D%2229%22%20cy%3D%22429%22%20r%3D%222.0%22%20fill%3D%22%23f0a8ca%22%20opacity%3D%220.37%22%2F%3E%3Ctext%20x%3D%2215%22%20y%3D%221876%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2244%22%20fill%3D%22%238e1f52%22%20opacity%3D%220.28%22%3E31%3C%2Ftext%3E%3Ccircle%20cx%3D%2272%22%20cy%3D%221340%22%20r%3D%222.1%22%20fill%3D%22%235c1035%22%20opacity%3D%220.40%22%2F%3E%3Ccircle%20cx%3D%2264%22%20cy%3D%221641%22%20r%3D%222.1%22%20fill%3D%22%23e589b5%22%20opacity%3D%220.25%22%2F%3E%3Cg%20transform%3D%22translate%2824.8%201614.3%29%20rotate%2817%2012%2012%29%20scale%281.70%29%22%20opacity%3D%220.34%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23f0a8ca%22%20stroke-width%3D%222.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2278%22%20y%3D%2254%22%20transform%3D%22rotate%28-87%2078%2054%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%226.5%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.24%22%3E%23DarkerPink%3C%2Ftext%3E%3Ccircle%20cx%3D%2225%22%20cy%3D%221182%22%20r%3D%221.4%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.22%22%2F%3E%3Ctext%20x%3D%2261%22%20y%3D%221772%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2231%22%20fill%3D%22%236b1140%22%20opacity%3D%220.26%22%3E31%3C%2Ftext%3E%3Ccircle%20cx%3D%2227%22%20cy%3D%22410%22%20r%3D%222.8%22%20fill%3D%22%237a1846%22%20opacity%3D%220.35%22%2F%3E%3Cg%20transform%3D%22translate%2879.3%201448.1%29%20rotate%2869%2012%2012%29%20scale%281.81%29%22%20opacity%3D%220.36%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23f0a8ca%22%20stroke-width%3D%222.2%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%2223%22%20cy%3D%22269%22%20r%3D%221.5%22%20fill%3D%22%23c9548c%22%20opacity%3D%220.24%22%2F%3E%3Ccircle%20cx%3D%2237%22%20cy%3D%221730%22%20r%3D%222.2%22%20fill%3D%22%23f0a8ca%22%20opacity%3D%220.27%22%2F%3E%3Ccircle%20cx%3D%2238%22%20cy%3D%22314%22%20r%3D%222.6%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.26%22%2F%3E%3Ctext%20x%3D%226%22%20y%3D%22633%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2220%22%20fill%3D%22%23bf4a7d%22%20opacity%3D%220.17%22%3E31%3C%2Ftext%3E%3Ctext%20x%3D%2222%22%20y%3D%221058%22%20transform%3D%22rotate%28-86%2022%201058%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%229.2%22%20fill%3D%22%236b1140%22%20opacity%3D%220.26%22%3E%23IAmThe31%3C%2Ftext%3E%3Ctext%20x%3D%2280%22%20y%3D%22680%22%20transform%3D%22rotate%28-90%2080%20680%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%226.2%22%20fill%3D%22%23e589b5%22%20opacity%3D%220.31%22%3Eincurable%3C%2Ftext%3E%3Cg%20transform%3D%22translate%28-18.0%20750.3%29%20rotate%28-48%2012%2012%29%20scale%281.55%29%22%20opacity%3D%220.29%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23d2649a%22%20stroke-width%3D%222.9%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2266%22%20y%3D%221070%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2225%22%20fill%3D%22%2393245a%22%20opacity%3D%220.24%22%3E31%3C%2Ftext%3E%3Cg%20transform%3D%22translate%2846.5%20191.1%29%20rotate%2827%2012%2012%29%20scale%282.02%29%22%20opacity%3D%220.35%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23b03a6e%22%20stroke-width%3D%222.1%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2256%22%20y%3D%221204%22%20transform%3D%22rotate%28-85%2056%201204%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%229.6%22%20fill%3D%22%235c1035%22%20opacity%3D%220.26%22%3E%23DarkerPink%3C%2Ftext%3E%3Cg%20transform%3D%22translate%288.3%201824.1%29%20rotate%28-51%2012%2012%29%20scale%282.14%29%22%20opacity%3D%220.39%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%235c1035%22%20stroke-width%3D%223.3%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2239%22%20y%3D%22450%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2232%22%20fill%3D%22%2393245a%22%20opacity%3D%220.18%22%3E31%3C%2Ftext%3E%3Ctext%20x%3D%224%22%20y%3D%22476%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2231%22%20fill%3D%22%23f0a8ca%22%20opacity%3D%220.24%22%3E31%3C%2Ftext%3E%3Cg%20transform%3D%22translate%2863.1%201479.7%29%20rotate%28-18%2012%2012%29%20scale%281.60%29%22%20opacity%3D%220.28%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23b03a6e%22%20stroke-width%3D%221.7%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%2227%22%20cy%3D%221618%22%20r%3D%222.0%22%20fill%3D%22%23b03a6e%22%20opacity%3D%220.30%22%2F%3E%3Cg%20transform%3D%22translate%2840.1%201204.9%29%20rotate%28-59%2012%2012%29%20scale%281.14%29%22%20opacity%3D%220.34%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23c9548c%22%20stroke-width%3D%222.5%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%2212%22%20cy%3D%22124%22%20r%3D%222.1%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.23%22%2F%3E%3Ccircle%20cx%3D%22-3%22%20cy%3D%22931%22%20r%3D%222.1%22%20fill%3D%22%235c1035%22%20opacity%3D%220.26%22%2F%3E%3Cg%20transform%3D%22translate%2869.9%201530.8%29%20rotate%28-12%2012%2012%29%20scale%282.33%29%22%20opacity%3D%220.24%22%3E%3Cpath%20d%3D%22M6.9%2020.4%20C8.6%2017.2%2010.6%2014.7%2012%2012.8%20C13.9%2010.7%2015.7%208.4%2015.6%205.6%20C15.5%203.5%2014.1%202%2012.3%202%20C10.5%202%209.1%203.5%209%205.6%20C8.9%208.4%2010.7%2010.7%2012%2012.8%20C13.4%2014.7%2015.4%2017.2%2017.1%2020.4%22%20fill%3D%22none%22%20stroke%3D%22%23c9548c%22%20stroke-width%3D%223.4%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fg%3E%3Ctext%20x%3D%2250%22%20y%3D%221395%22%20transform%3D%22rotate%28-92%2050%201395%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%227.2%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.22%22%3Eincurable%3C%2Ftext%3E%3Ctext%20x%3D%2252%22%20y%3D%22141%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2245%22%20fill%3D%22%23bf4a7d%22%20opacity%3D%220.17%22%3E31%3C%2Ftext%3E%3Ctext%20x%3D%2210%22%20y%3D%22806%22%20transform%3D%22rotate%28-91%2010%20806%29%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22800%22%20font-size%3D%229.2%22%20fill%3D%22%235c1035%22%20opacity%3D%220.32%22%3E31%20a%20day%3C%2Ftext%3E%3Ccircle%20cx%3D%224%22%20cy%3D%221871%22%20r%3D%222.6%22%20fill%3D%22%23d2649a%22%20opacity%3D%220.29%22%2F%3E%3Ccircle%20cx%3D%22-3%22%20cy%3D%221722%22%20r%3D%222.3%22%20fill%3D%22%23a02a61%22%20opacity%3D%220.36%22%2F%3E%3Ccircle%20cx%3D%2257%22%20cy%3D%22899%22%20r%3D%221.9%22%20fill%3D%22%23c9548c%22%20opacity%3D%220.36%22%2F%3E%3Ctext%20x%3D%22-14%22%20y%3D%22648%22%20font-family%3D%22Archivo%2C%20Helvetica%2C%20Arial%2C%20sans-serif%22%20font-weight%3D%22900%22%20font-size%3D%2231%22%20fill%3D%22%23c9548c%22%20opacity%3D%220.29%22%3E31%3C%2Ftext%3E%3C%2Fsvg%3E");
  background-size: 100% auto;
  background-repeat: repeat-y;
  transform: translate3d(0, var(--art-y, 0px), 0);
}
@media (prefers-reduced-motion: reduce) {
  .social-rail__icon::before { transform: none; }
}

/* --- The header on a narrow screen -------------------------------------- */

/* Confirmed on a real phone, not an emulator: the bar was wider than the
   screen. The brand would not shrink, the four controls beside it are all
   fixed-size, and nothing wrapped — so the logo was cut off the left edge and
   the whole page slid sideways under the thumb. A page that moves when you
   scroll it is the thing people notice before anything else.
   The brand shrinks first, the tagline goes before the name does, and the bar
   is told outright that it may not overflow. */
@media (max-width: 40em) {
  .site-header__bar { gap: var(--sp-3); min-width: 0; }
  .brand { flex: 0 1 auto; min-width: 0; gap: var(--sp-2); }
  .brand > span { min-width: 0; }
  .brand__name {
    /* display: block is what makes the two lines below do anything at all.
       overflow and text-overflow have no effect on a non-replaced inline box,
       so this rule was inert: the wordmark kept its full width and simply ran
       underneath the search button — 24px of overlap at 320px. */
    display: block;
    font-size: 1rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* The hashtag is the first thing to go: the logo beside it already says
     who this is, and losing it buys the width the buttons need. */
  .brand__tag { display: none; }
  .site-header__actions { gap: 4px; min-width: 0; }
  .site-header__actions .btn { padding-inline: var(--sp-3); font-size: 0.72rem; }
  .icon-btn { width: 2.5rem; height: 2.5rem; }
  /* Search and the theme switch move into the drawer.
     Four controls plus a wordmark do not fit beside each other on a phone, and
     the ways of forcing them to all cost something real: shrinking the buttons
     took the smallest tap target to 24px, and hiding the wordmark gave up the
     name of the charity. Neither is worth it for a search button, because the
     menu is where a phone user looks for one anyway.
     What is left in the bar is what a visitor came for — the charity, Donate,
     and the way into everything else. Nothing is removed: both controls are in
     the drawer, driven by the same delegated handlers, one tap further away. */
  .site-header__actions [data-search-open],
  .site-header__actions [data-theme-toggle] { display: none; }
}

/* The drawer's own row: the two that moved, plus close. */
.drawer__tools { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
@media (min-width: 40.0625em) {
  .drawer__tools [data-search-open],
  .drawer__tools [data-theme-toggle] { display: none; }
}

/* Belt and braces, at every width: the header is never the reason the page
   scrolls sideways. */
.site-header, .site-header__bar { max-width: 100%; }
.site-header { overflow-x: clip; }

/* --- Drawer submenus ----------------------------------------------------- */

/* The rule down the left of a submenu was touching the words. A line that
   close reads as a crossing-out rather than as grouping, and on a phone the
   text starts hard against the edge of the tap target. */
.drawer .drawer__sub { padding-left: var(--sp-5); }
.drawer .drawer__sub .is-child a { padding-left: var(--sp-4); }

/* --- Mobile: nothing worth reading is hidden ----------------------------- */

/* Below 1100px the whole artwork layer was display:none, and Jo Taylor went
   with it — her name, the sentence saying she recorded her own film, and the
   link to it. A phone visitor never knew that page existed.
   The thirty-one faces are decoration and genuinely need the width they do not
   have here, so they stay behind. What was never decoration is the woman the
   panel is about, so on a phone she comes out from behind the picture and sits
   under the copy as an ordinary card. */
@media (max-width: 1099.98px) {
  .scrolly__art {
    display: block;
    position: static;
    inset: auto;
    padding: 0;
    pointer-events: auto;
  }
  .scrolly__faces { display: none; }
  .scrolly__kept {
    position: static;
    opacity: 1;
    transform: none;
    transition: none;
    max-width: none;
    margin-top: var(--sp-5);
    padding: var(--sp-5);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: var(--radius-lg);
    background: rgba(28, 3, 16, 0.42);
  }
  .scrolly__kept .btn { margin-top: var(--sp-4); }
}

/* Tap targets. A link in a list was 22px tall — half the 44px a finger needs,
   and the rows sat close enough together that the wrong one was easy to hit.
   Padding rather than height, so the text stays where the design put it and
   only the target around it grows. */
@media (max-width: 48em) {
  .link-list a,
  .route a,
  .prose > ul > li > a:only-child,
  .footer__nav a,
  .site-footer a { padding-block: 0.55rem; display: inline-block; }
}

/* --- On this page, on a phone -------------------------------------------- */

/* The contents rail was display:none below 1024px. On /i-am-the-31/ that is a
   hundred and thirty-eight sections with no way to reach any of them except by
   scrolling past all of them.
   It is a <details> now, so the same markup is a rail on a desktop and a
   disclosure on a phone. Closed to begin with, because opened it would push the
   article off the screen. */
@media (max-width: 1023.98px) {
  .toc {
    display: block;
    /* .layout-aside is a grid with the article first, so in one column the
       contents landed under all 138 sections — 39,000px down, which is not
       navigation, it is an afterword. */
    order: -1;
    margin: 0 0 var(--sp-6);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-sunken);
    overflow: hidden;
  }
  .toc > summary {
    cursor: pointer; list-style: none;
    padding: var(--sp-4) var(--sp-5);
    min-height: 2.75rem;
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
    font-family: var(--font-display); font-weight: 700;
    font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.12em;
    color: var(--text-muted); margin: 0;
  }
  .toc > summary::-webkit-details-marker { display: none; }
  /* One glyph for both states, turned rather than swapped — the same idea the
     expandable sections use, so the page has one language for opening things. */
  .toc > summary::after {
    content: "+"; font-size: 1.25rem; line-height: 1; color: var(--text-faint);
    transition: transform var(--dur-2) var(--ease);
  }
  .toc[open] > summary::after { transform: rotate(45deg); }
  .toc > ol {
    max-height: 55vh; overflow-y: auto;
    margin: 0; padding: 0 var(--sp-5) var(--sp-4);
    border-left: 0;
  }
  .toc a { padding-block: 0.5rem; display: block; }
}

/* On a desktop it is the rail it always was: the summary is not a control, and
   the list shows whether or not the element is open. */
@media (min-width: 1024px) {
  .toc > summary { list-style: none; }
  .toc > summary::-webkit-details-marker { display: none; }
  .toc:not([open]) > ol { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .toc > summary::after { transition: none; }
}
