/* ============================================================
   THE DR PERSE AWARD - shared stylesheet
   Style system: warm paper, deep plum, one warm secondary.
   Flat surfaces only. Hairline rules do all the dividing work.

   PALETTE LOGIC
   Plum is the primary: display headlines, links, buttons, the
   sponsor wall. Ochre is the single secondary, used only to mark
   things that are non-negotiable (hard deadlines, required steps)
   so it never competes with plum. Ink is a purple-black, not a
   true black, so body copy sits in the same family as the accent.
   ============================================================ */

:root {
  /* --- palette --- */
  --cream:   #fff8f1;   /* page + card surface */
  --cream-2: #fffcf8;   /* barely-there lift for inset panels */
  --wash:    #f5effb;   /* plum tint - sponsor wall, accent panels */
  --ash:     #e7e0ec;   /* every hairline, every border */
  --ash-2:   #cfc5d6;   /* hairline, emphasised */
  --ink:     #1a1220;   /* body text, strokes - a purple-black */
  --ink-60:  #5e5566;   /* secondary text */
  --plum:    #5b21b6;   /* PRIMARY: headlines, links, buttons */
  --plum-d:  #4c1d95;   /* primary, pressed */
  --plum-br: #7c3aed;   /* primary, brightened - markers, numerals */
  --ochre:   #a8571b;   /* SECONDARY: hard deadlines, required steps */


  /* --- type --- */
  --display: "Fraunces", "Times New Roman", serif;
  --ui: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  /* --- rhythm --- */
  --pad: clamp(1.5rem, 7vw, 9rem);      /* 144px horizontal page padding at full size */
  --gap: clamp(4.5rem, 11vw, 9.375rem); /* 150px section gaps at full size */
  --max: 1200px;
  --measure: 37.5rem;                   /* 600px narrow body column */
}

/* ------------------------------------------------------------ reset */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; overflow-x: clip; }
body, h1, h2, h3, h4, p, ul, ol, li, figure, dl, dd { margin: 0; padding: 0; }
ul, ol { list-style: none; }
img { max-width: 100%; display: block; }

body {
  overflow-x: clip;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--ui);
  font-weight: 400;
  font-size: 1.0625rem;
  line-height: 1.5;
  letter-spacing: -0.02em;
  font-feature-settings: "clig" 1, "liga" 1;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--plum); color: var(--cream); }

/* ------------------------------------------------------------ layout */
.wrap { max-width: var(--max); margin-inline: auto; padding-inline: var(--pad); }
/* Positioning context for the gutter treats. Scoped to main so the
   header's absolutely-positioned mobile nav keeps resolving against
   the sticky header, not against its wrap. */
main section > .wrap { position: relative; }
.measure { max-width: var(--measure); }
.rule { border: 0; border-top: 1px solid var(--ash); margin: 0; }
.stack > * + * { margin-top: 1.8125rem; } /* 29px paragraph rhythm */

main section { padding-block: var(--gap); }
main section + section { border-top: 1px solid var(--ash); }

/* Numbered section head: the numeral sits out in the left margin,
   the way a printed poster captions its panels. */
.block { display: grid; gap: 2.5rem 3.5rem; grid-template-columns: 1fr; }
@media (min-width: 62rem) {
  .block { grid-template-columns: 5.5rem minmax(0, 1fr); }
}
.block-num {
  font-family: var(--ui);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-60);
  padding-top: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ type */
.eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-60);
}
.eyebrow .dot { color: var(--plum); }
.eyebrow.accent { color: var(--plum); }
.eyebrow.warm { color: var(--ochre); }   /* required / non-negotiable */

/* Ochre is reserved for the handful of things that cannot slip. */
.hard { color: var(--ochre); font-weight: 600; }

/* Display type carries the primary colour. Body copy stays ink,
   so the purple reads as brand rather than as a legibility problem. */
.display, h1.display {
  font-family: var(--display);
  font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 0;
  font-weight: 200;
  font-size: clamp(3.25rem, 9.5vw, 7.5rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--plum);
  text-wrap: balance;
}
h2 {
  font-family: var(--display);
  font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 0;
  font-weight: 200;
  font-size: clamp(2.125rem, 4.6vw, 3.5rem);
  line-height: 1;
  letter-spacing: -0.025em;
  color: var(--plum);
  text-wrap: balance;
}
h3 {
  font-family: var(--ui);
  font-weight: 600;
  font-size: 1.125rem;
  line-height: 1.3;
}
h4 { font-family: var(--ui); font-weight: 600; font-size: 1rem; }

.lede {
  font-size: clamp(1.1875rem, 2vw, 1.5rem);
  line-height: 1.35;
  font-weight: 300;
  color: var(--ink);
}
p { color: var(--ink-60); }
p strong, li strong { color: var(--ink); font-weight: 600; }
.ink { color: var(--ink); }

a { color: var(--plum); text-decoration: none; text-underline-offset: 0.2em; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--plum); outline-offset: 3px; border-radius: 2px; }

.skip {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--cream);
  padding: 0.75rem 1.25rem; border-radius: 60px; z-index: 99;
}
.skip:focus { left: var(--pad); top: 0.75rem; }

/* ------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; gap: 0.625rem;
  font-family: var(--ui); font-size: 0.9375rem; font-weight: 500;
  letter-spacing: -0.01em;
  padding: 0.8125rem 1.5rem;
  border-radius: 60px;
  border: 1px solid var(--ink);
  background: transparent; color: var(--ink);
  text-decoration: none;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.btn:hover { background: var(--ink); color: var(--cream); text-decoration: none; }
.btn-primary { background: var(--plum); border-color: var(--plum); color: var(--cream); }
.btn-primary:hover { background: var(--plum-d); border-color: var(--plum-d); color: var(--cream); }
.btn-sm { padding: 0.5625rem 1.125rem; font-size: 0.875rem; }
.btn .arrow { font-size: 1.05em; line-height: 1; }
.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* ------------------------------------------------------------ header */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--cream);
  border-bottom: 1px solid var(--ash);
}
.site-header .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; min-height: 4.5rem;
}
.wordmark {
  font-family: var(--display);
  font-variation-settings: "opsz" 144;
  font-weight: 300; font-size: 1.375rem; letter-spacing: -0.03em;
  color: var(--plum); text-decoration: none; white-space: nowrap;
  display: flex; align-items: center; gap: 0.625rem;
}
/* The crest is already the right purple, so it needs no treatment — just
   room to breathe and a size that holds its detail at small scale. */
.crest { width: auto; height: 2.125rem; flex: none; }
@media (max-width: 26rem) {
  /* the name alone carries the header once the screen is very narrow */
  .wordmark span { font-size: 1.125rem; }
  .crest { height: 1.75rem; }
}
.crest--footer { height: 4.5rem; margin-bottom: 1.75rem; }
.wordmark:hover { text-decoration: none; color: var(--plum-d); }
.nav { display: flex; align-items: center; gap: 2rem; }
.nav a { font-size: 0.9375rem; font-weight: 400; color: var(--ink); padding-block: 0.25rem; }
.nav a:hover { color: var(--plum); text-decoration: none; }
.nav a[aria-current="page"] { color: var(--plum); }
.nav-toggle { display: none; }

@media (max-width: 61.99rem) {
  .nav { display: none; }
  .nav-toggle {
    display: inline-flex; align-items: center; gap: 0.5rem;
    background: none; border: 1px solid var(--ink); border-radius: 60px;
    font: inherit; font-size: 0.875rem; padding: 0.5rem 1rem; cursor: pointer;
    color: var(--ink);
  }
  .site-header.open .nav {
    display: flex; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; left: 0; right: 0; top: 100%;
    background: var(--cream); border-bottom: 1px solid var(--ash);
    padding: 0.5rem var(--pad) 1.5rem;
  }
  .site-header.open .nav a { padding-block: 0.875rem; border-bottom: 1px solid var(--ash); }
  .site-header.open .nav .btn { margin-top: 1rem; justify-content: center; border: 1px solid var(--plum); }
}

/* ------------------------------------------------------------ hero */
.hero { padding-block: clamp(3.5rem, 9vw, 7.5rem) clamp(3rem, 7vw, 5.5rem); }
.hero .display { margin-top: 1.75rem; }
.hero .lede { margin-top: 2.25rem; max-width: var(--measure); }
.hero .btn-row { margin-top: 2.5rem; }

/* Page head for interior pages */
.page-head { padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2.5rem, 5vw, 4rem); }
.page-head h1 { margin-top: 1.5rem; }
.page-head .lede { margin-top: 1.75rem; max-width: var(--measure); }

/* Fact strip - flat cream cells, hairlines only */
.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  border-top: 1px solid var(--ash);
  border-left: 1px solid var(--ash);
}
.facts > div {
  border-right: 1px solid var(--ash);
  border-bottom: 1px solid var(--ash);
  padding: 1.5rem 1.5rem 1.75rem;
}
.facts dt { font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-60); font-weight: 500; }
.facts dd {
  margin-top: 0.625rem; font-family: var(--display); font-variation-settings: "opsz" 144;
  font-weight: 300; font-size: clamp(1.5rem, 2.6vw, 2rem); line-height: 1.05; letter-spacing: -0.03em;
  color: var(--ink);
}
.facts dd small { display: block; font-family: var(--ui); font-size: 0.875rem; letter-spacing: -0.02em; color: var(--ink-60); margin-top: 0.375rem; font-weight: 400; }

/* ------------------------------------------------------------ rows */
.rows { border-top: 1px solid var(--ash); }
.rows > li, .rows > div {
  display: grid; gap: 0.5rem 2.5rem;
  grid-template-columns: 1fr;
  padding: 1.625rem 0;
  border-bottom: 1px solid var(--ash);
}
@media (min-width: 48rem) {
  .rows > li, .rows > div { grid-template-columns: 13rem minmax(0, 1fr); align-items: baseline; }
}
.rows .key { font-weight: 500; color: var(--ink); font-size: 0.9375rem; font-variant-numeric: tabular-nums; }
.rows .key .tag {
  display: block; font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-60); font-weight: 500; margin-bottom: 0.375rem;
}
.rows .val h3 { margin-bottom: 0.5rem; }
.rows .val p { font-size: 1rem; }
.rows .weight {
  font-family: var(--display); font-variation-settings: "opsz" 144; font-weight: 300;
  font-size: 2rem; line-height: 1; letter-spacing: -0.03em; color: var(--plum-br);
}

/* ------------------------------------------------------------ document links */
.docs { border-top: 1px solid var(--ash); }
.docs a {
  display: grid; gap: 0.375rem 2rem; grid-template-columns: minmax(0,1fr) auto;
  align-items: center;
  padding: 1.5rem 0;
  border-bottom: 1px solid var(--ash);
  color: var(--ink); text-decoration: none;
  transition: padding-inline-start 140ms ease, color 140ms ease;
}
.docs a:hover { text-decoration: none; color: var(--plum); padding-inline-start: 0.75rem; }
.docs .doc-title { font-size: 1.25rem; font-weight: 500; letter-spacing: -0.025em; }
.docs .doc-note { grid-column: 1; font-size: 0.9375rem; color: var(--ink-60); }
.docs .doc-go { grid-row: 1 / span 2; grid-column: 2; font-size: 1.25rem; color: var(--plum); }

/* ------------------------------------------------------------ prose */
.prose { max-width: var(--measure); }
.prose > * + * { margin-top: 1.8125rem; }
.prose h3 { margin-top: 2.75rem; }
.prose h3:first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 0; }
.prose li { position: relative; padding-left: 1.75rem; color: var(--ink-60); }
.prose li + li { margin-top: 0.875rem; }
.prose ul > li::before {
  content: ""; position: absolute; left: 0; top: 0.6875rem;
  width: 0.5rem; height: 1px; background: var(--plum-br);
}
.prose ol { counter-reset: n; }
.prose ol > li { counter-increment: n; }
.prose ol > li::before {
  content: counter(n, decimal-leading-zero);
  position: absolute; left: 0; top: 0;
  font-size: 0.75rem; letter-spacing: 0.08em; color: var(--plum-br);
  font-weight: 500; line-height: 1.9;
  font-variant-numeric: tabular-nums;
}

/* Inset panel - still flat, defined by a hairline alone */
.panel {
  background: var(--cream-2);
  border: 1px solid var(--ash);
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
.panel .eyebrow { margin-bottom: 1rem; }
.panel > * + * { margin-top: 1rem; }
.panel.accent { border-color: var(--plum); background: var(--wash); }
.panel.accent .eyebrow { color: var(--plum); }
.panel.warn { border-color: var(--ochre); }
.panel.warn .eyebrow { color: var(--ochre); }

/* Table of contents for the long rule pages */
.toc { border-top: 1px solid var(--ash); }
.toc li { border-bottom: 1px solid var(--ash); }
.toc a { display: flex; justify-content: space-between; gap: 1.5rem; padding: 0.9375rem 0; color: var(--ink); font-size: 0.9375rem; }
.toc a:hover { color: var(--plum); text-decoration: none; }
.toc .n { color: var(--ink-60); font-variant-numeric: tabular-nums; }

/* Multi-column info grid */
.cols { display: grid; gap: 2.5rem 3.5rem; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
.cols .col h3 { margin-bottom: 0.75rem; }
.cols .col p { font-size: 1rem; }
.cols .col .eyebrow { margin-bottom: 0.75rem; }

/* FAQ */
details.qa { border-bottom: 1px solid var(--ash); }
details.qa:first-of-type { border-top: 1px solid var(--ash); }
details.qa summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: baseline; gap: 2rem;
  padding: 1.5rem 0;
  font-size: 1.125rem; font-weight: 500; letter-spacing: -0.025em; color: var(--ink);
}
details.qa summary::-webkit-details-marker { display: none; }
details.qa summary::after { content: "+"; color: var(--plum); font-size: 1.375rem; line-height: 1; font-weight: 300; }
details.qa[open] summary::after { content: "\2013"; }
details.qa summary:hover { color: var(--plum); }
details.qa .qa-body { padding-bottom: 1.75rem; max-width: var(--measure); }
details.qa .qa-body > * + * { margin-top: 1rem; }

/* ------------------------------------------------------------ sponsors
   The sponsor wall is the one full-bleed tinted surface on the site.
   Names are set as typographic wordmarks in the display serif rather
   than as logos, so the wall stays consistent no matter what artwork
   each sponsor supplies. Swap a <span> for an <img> if you are given
   a real logo - the cell sizing already allows for it. */
.sponsors { background: var(--wash); border-top: 1px solid var(--ash); }
main section.sponsors + section { border-top: 1px solid var(--ash); }

.sponsor-tier + .sponsor-tier { margin-top: 3.5rem; }
.sponsor-tier > .eyebrow { color: var(--plum); margin-bottom: 1.25rem; }

.sponsor-grid {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  border-top: 1px solid var(--ash-2);
  border-left: 1px solid var(--ash-2);
}
.sponsor-grid > * {
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  min-height: 8rem; padding: 1.75rem 1.25rem;
  border-right: 1px solid var(--ash-2);
  border-bottom: 1px solid var(--ash-2);
  font-family: var(--display); font-variation-settings: "opsz" 144;
  font-weight: 300; font-size: 1.5rem; line-height: 1.1; letter-spacing: -0.03em;
  color: var(--plum); text-decoration: none;
  transition: background 140ms ease, color 140ms ease;
}
.sponsor-grid a:hover { background: var(--plum); color: var(--wash); text-decoration: none; }
.sponsor-grid img { max-height: 3.5rem; width: auto; object-fit: contain; }

/* Lead tier gets one wide cell and larger type. */
.sponsor-tier.lead .sponsor-grid { grid-template-columns: 1fr; }
.sponsor-tier.lead .sponsor-grid > * { min-height: 11rem; font-size: clamp(2rem, 4vw, 3rem); font-weight: 200; }

/* Supporters degrade to a plain typographic list. */
.sponsor-list {
  display: flex; flex-wrap: wrap; gap: 0.5rem 2rem;
  font-size: 1rem; color: var(--ink);
}
.sponsor-list li { display: flex; align-items: center; gap: 2rem; }
.sponsor-list li + li::before { content: ""; }

/* CTA band */
.cta { text-align: center; }
.cta h2 { margin-bottom: 1.5rem; }
.cta p { margin-inline: auto; max-width: 32rem; }
.cta .btn-row { justify-content: center; margin-top: 2.25rem; }

/* ------------------------------------------------------------ footer */
.site-footer { border-top: 1px solid var(--ash); padding-block: 4rem 3rem; }
.footer-mark {
  font-family: var(--display); font-variation-settings: "opsz" 144;
  font-weight: 200; font-size: clamp(3rem, 12vw, 9rem); line-height: 0.9;
  letter-spacing: -0.04em; color: var(--plum); padding-bottom: 2.5rem;
}
.footer-grid {
  display: grid; gap: 2.5rem 3rem;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  padding-bottom: 3rem;
}
.footer-grid h4 { font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-60); font-weight: 500; margin-bottom: 1rem; }
.footer-grid li + li { margin-top: 0.625rem; }
.footer-grid a { color: var(--ink); font-size: 0.9375rem; }
.footer-grid a:hover { color: var(--plum); text-decoration: none; }
.footer-base {
  border-top: 1px solid var(--ash); padding-top: 1.75rem;
  display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between;
  font-size: 0.875rem; color: var(--ink-60);
}

/* ============================================================
   MOTION
   The brief here is print, not app: things arrive the way ink
   settles onto paper. Short distances, no bounce, one easing
   curve throughout, and hairlines that draw themselves across
   the page rather than fading in.

   HOW IT STAYS SAFE
   Nothing is hidden by CSS alone. The inline <head> script adds
   .motion to <html> whenever animation is wanted, and that class
   is the ONLY gate — there is deliberately no second
   prefers-reduced-motion media query behind it, because that made
   the footer toggle a dead control on any machine reporting
   "reduce": the class went on and still nothing could move. If
   reveal.js never runs, a 2.6s timer adds .motion-fallback,
   which flips the same properties back and everything appears.
   Custom properties inherit, so that fallback is one rule
   rather than a duplicate of every selector below.
   ============================================================ */

html.motion {
  --rv-o: 0;                      /* reveal opacity, hidden      */
  --rv-t: translateY(40px);       /* reveal offset, hidden       */
  --rv-line: translateY(125%);    /* headline line mask, hidden  */
  --rv-sx: 0;                     /* hairline scale, undrawn     */
}
/* Safety net: reveal.js failed to boot, so show everything. */
html.motion.motion-fallback:not(.motion-ready) {
  --rv-o: 1; --rv-t: none; --rv-line: none; --rv-sx: 1;
}

/* --- the reveal set ------------------------------------------------
   Kept as explicit structural selectors so the hiding happens in the
   first style pass. Tagging these from JS would flash. reveal.js
   queries this same list; edit both together. */
main .block-num,
main h2,
main .lede,
main .page-head > .wrap > .eyebrow,
main .hero > .wrap > .eyebrow,
main .btn-row,
main .measure,
main .facts > div,
main .rows > li,
main .cols .col,
main .docs a,
main .toc li,
main .prose,
main .panel,
main details.qa,
main .sponsor-tier,
.site-footer .footer-mark:not([data-type]) {
  opacity: var(--rv-o, 1);
  transform: var(--rv-t, none);
  transition:
    opacity   1500ms cubic-bezier(.16, 1, .3, 1) var(--d, 0ms),
    transform 1500ms cubic-bezier(.16, 1, .3, 1) var(--d, 0ms);
}
main .block-num.in,
main h2.in,
main .lede.in,
main .page-head > .wrap > .eyebrow.in,
main .hero > .wrap > .eyebrow.in,
main .btn-row.in,
main .measure.in,
main .facts > div.in,
main .rows > li.in,
main .cols .col.in,
main .docs a.in,
main .toc li.in,
main .prose.in,
main .panel.in,
main details.qa.in,
main .sponsor-tier.in,
.site-footer .footer-mark:not([data-type]).in {
  opacity: 1;
  transform: none;
}

/* --- headline line mask --------------------------------------------
   Each line of a display heading rises out of its own clipped box.
   The padding/margin pair widens the clip just enough to let
   descenders through without moving the line. */
.display .line {
  display: block;
  overflow: hidden;
  /* Fraunces descenders drop well below a 0.95 line box, so the clip
     is widened and then pulled back by an equal negative margin —
     descenders survive, layout is untouched. */
  padding-bottom: 0.2em;
  margin-bottom: -0.2em;
}
.display .line > span {
  display: block;
  transform: var(--rv-line, none);
  transition: transform 1900ms cubic-bezier(.16, 1, .3, 1) var(--d, 0ms);
}
.display.in .line > span { transform: none; }
/* A heading being typed does not also rise out of its mask — one entrance
   each. The clip stays, so descenders are still handled. */
.display[data-type] .line > span { transform: none; transition: none; }

/* --- section hairlines draw across ---------------------------------- */
html.motion main section + section { border-top-color: transparent; position: relative; }
html.motion main section + section::before {
  content: "";
  position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--ash);
  transform: scaleX(var(--rv-sx, 1));
  transform-origin: left center;
  transition: transform 2400ms cubic-bezier(.16, 1, .3, 1);
}
html.motion main section + section.in::before { transform: scaleX(1); }
html.motion.motion-fallback:not(.motion-ready) main section + section {
  border-top-color: var(--ash);
}

/* --- FAQ panels open with a small settle ---------------------------- */
details.qa[open] .qa-body { animation: qa-settle 620ms cubic-bezier(.16, 1, .3, 1) both; }
@keyframes qa-settle {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   THE PRIZE
   The £1,000 is the loudest thing on the home page: the figure
   is set larger than any headline on the site, and the tagline
   that used to be the hero drops to a supporting size beneath
   it. Cartoon banknotes drift around the figure, and a slow
   fall of them crosses the whole viewport whenever a prize
   section is on screen.
   ============================================================ */

.prize { position: relative; margin-top: 1.5rem; }
.prize-kicker { margin-bottom: 0.5rem; }

.prize-figure {
  font-family: var(--display);
  font-variation-settings: "opsz" 144, "SOFT" 0, "WONK" 0;
  font-weight: 200;
  font-size: clamp(5rem, 18vw, 15rem);
  line-height: 0.82;
  letter-spacing: -0.045em;
  color: var(--plum);
  display: flex; align-items: flex-start; gap: 0.02em;
  font-variant-numeric: tabular-nums lining-nums;
}
.prize-figure .cur { font-size: 0.52em; line-height: 1.1; font-weight: 300; }
.prize-sub {
  font-family: var(--display);
  font-variation-settings: "opsz" 144;
  font-weight: 200;
  font-size: clamp(1.75rem, 4vw, 3rem);
  line-height: 1.1; letter-spacing: -0.03em;
  color: var(--ink);
  margin-top: 0.25rem;
}
.prize-sub em { font-style: normal; color: var(--plum); }

/* The tagline steps back so the number can lead. */
.display--sub { font-size: clamp(2rem, 5vw, 3.5rem); }

/* Notes drifting around the hero figure, distinct from the falling rain.
   No negative z-index: the floats come first in the DOM and the text after,
   so with both positioned the text paints on top without needing to escape
   a stacking context. */
/* Horizontal inset stays at 0 so a float can never reach past the content
   box; only the vertical bleed is negative. */
.prize-floats { position: absolute; inset: -12% 0 -18% 0; pointer-events: none; z-index: 0; }
.prize-floats .note-float { position: absolute; }
.prize-kicker, .prize-figure, .prize-sub { position: relative; z-index: 1; }

/* ============================================================
   MONEY RAIN
   A fixed, pointer-transparent layer that fades in while any
   [data-money] section is on screen. Fixed positioning means it
   is not clipped by the page and cannot add a scrollbar; the
   layer clips its own contents.
   ============================================================ */

.money-rain {
  position: fixed; inset: 0;
  z-index: 40;                /* under the sticky header at 50 */
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 1200ms ease;
}
.money-rain.on { opacity: 1; }

.note {
  position: absolute; top: 0;
  width: var(--w, 4.5rem);
  will-change: transform;
}
.note-art { display: block; width: 100%; height: auto; }

/* Three properties, three animations, no conflicts: the outer note
   falls (translate), the inner wrapper sways (transform), the artwork
   tumbles (rotate). */
.money-rain .note {
  animation: note-fall var(--dur, 15s) linear var(--delay, 0s) infinite;
}
.money-rain .note-i {
  display: block;
  animation:
    note-sway var(--sway, 7s) ease-in-out var(--delay, 0s) infinite alternate,
    note-spin var(--spin, 12s) linear var(--delay, 0s) infinite;
}
@keyframes note-fall {
  from { translate: 0 -25vh; }
  to   { translate: 0 125vh; }
}
@keyframes note-sway {
  from { transform: translateX(-1.75rem); }
  to   { transform: translateX(1.75rem); }
}
@keyframes note-spin {
  from { rotate: var(--r0, 0deg); }
  to   { rotate: calc(var(--r0, 0deg) + 360deg); }
}

/* Hero notes only breathe — they never fall. */
.prize-floats .note-art {
  animation: prize-bob var(--dur, 14s) ease-in-out var(--delay, 0s) infinite;
  rotate: var(--r0, 0deg);
}
@keyframes prize-bob {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -22px; }
}

/* No motion (OS preference, JS off, or the visitor's own choice): no
   falling layer at all, and the hero notes sit still. Keyed on the class
   rather than the media query so the toggle can override the OS. */
html:not(.motion) .money-rain { display: none; }

/* ============================================================
   THE ROLL
   A doughnut rolls across the stage and uncovers the sponsors
   behind it.

   HOW THE WIPE WORKS
   .roll-veil is a sheet of page-coloured cream over the whole
   stage, masked by a linear gradient whose edge sits at --wipe.
   roll.js sets --wipe to the doughnut's centre each frame, so
   everything the doughnut has already passed is clear and
   everything ahead of it is still covered. The veil is the page
   colour, so it never reads as a panel - it just looks like the
   sponsors were always there, under something being swept away.
   ============================================================ */

/* The two driven properties are declared HERE, on the section, because that is
   the element roll.js writes them to. Declaring them again on .roll-stick would
   shadow the values being set and the wipe would silently never move. */
main section.roll {
  padding-block: 0;
  --wipe: 0px;
  --roll-line: 72svh;
}
@supports not (height: 1svh) {
  main section.roll { --roll-line: 72vh; }
}
.roll-track { height: 200vh; position: relative; }
@media (max-width: 61.99rem) {
  /* two full screens of scrolling for one rolling doughnut is too much on a
     phone, where there is far more scrolling to get through overall */
  .roll-track { height: 130vh; }
}
.roll-stick {
  position: sticky; top: 0;
  height: 100vh;
  height: 100svh;
  min-height: 26rem;
  overflow: hidden;          /* the doughnut starts and ends off stage */
  display: grid;
}

.roll-reveal {
  grid-area: 1 / 1;
  align-self: center;
  position: relative; z-index: 0;
}
.roll-names {
  display: flex; flex-wrap: wrap; gap: 0.5rem 2.5rem;
  margin-top: 1.75rem;
  font-family: var(--display);
  font-variation-settings: "opsz" 144;
  font-weight: 300;
  font-size: clamp(1.375rem, 3.2vw, 2.25rem);
  line-height: 1.15;
  letter-spacing: -0.03em;
  color: var(--plum);
}
.roll-reveal .measure { margin-top: 1.75rem; }

/* The hairline the doughnut rolls along. It sits UNDER the veil, so it draws
   itself in behind the doughnut exactly like the sponsors do. */
/* translate, not margin-top: a percentage margin resolves against the
   container's WIDTH, which put the line far below a short, wide stage. */
.roll-line {
  grid-area: 1 / 1;
  align-self: start;
  z-index: 0;
  translate: 0 var(--roll-line);
  height: 1px; width: 100%;
  background: var(--ash-2);
}

.roll-veil {
  grid-area: 1 / 1;
  z-index: 1;
  background: var(--cream);
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to right,
                        rgba(0,0,0,0) calc(var(--wipe) - 10px), #000 var(--wipe));
          mask-image: linear-gradient(to right,
                        rgba(0,0,0,0) calc(var(--wipe) - 10px), #000 var(--wipe));
}

/* Sits on the line: bottom edge on the hairline, hence the -100% translate. */
.roll-donut {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: start;
  z-index: 2;
  width: clamp(6.5rem, 15vmin, 11rem);
  height: auto;
  max-width: none;
  /* Sits ON the line: down to the line, then back up by its own height.
     `translate` is its own property, so the translateX + rotate that roll.js
     writes to `transform` compose with this instead of overwriting it. */
  translate: 0 calc(var(--roll-line) - 100%);
  pointer-events: none;
  will-change: transform;
}

/* No JS, no artwork, or no motion: no veil, no doughnut, sponsors read. */
.roll.roll-open .roll-veil,
.roll.roll-open .roll-donut { display: none; }

html:not(.motion) .roll-veil,
html:not(.motion) .roll-donut { display: none; }

/* ============================================================
   TREATS
   Doughnuts, pizza and sweets that pop in as you scroll, drawn
   as flat riso-style spot illustrations in the site palette with
   hairline ink outlines, so they read as printed poster
   decoration rather than clip art.

   They live in the outer page gutter and never enter the reading
   column. The gutter is var(--pad) wide — up to 144px — and a
   treat is at most 88px, so they cannot widen the page. Below
   62rem the gutter is too narrow and they are hidden outright.

   Markup is injected by treats.js; artwork lives there too.
   ============================================================ */

:root {
  /* Treat-only spot colours. The first four are the site palette;
     terracotta is the one hue added for food, and it sits next to
     ochre so the set still reads as one print run. */
  --t-dough:  #e0a96d;
  --t-crust:  #d9922f;
  --t-cheese: #f2c14e;
  --t-sauce:  #c2410c;   /* terracotta */
  --t-icing:  var(--plum-br);
}

.treat {
  position: absolute;
  z-index: 1;
  /* Default size exactly fills the page gutter, whatever the viewport.
     The large tier below takes over once there is real room. */
  --treat-w: calc(var(--pad) - 1.25rem);
  width: var(--treat-w);
  pointer-events: none;
  /* Individual transform properties, not a `transform` shorthand: the hidden
     state has to be declared on <html> for the fallback gate to reach it, and
     a var() inside a shorthand there would resolve --rot against <html> —
     which has none — giving every treat the same angle. scale/rotate/translate
     resolve per element, so each treat keeps its own tilt and direction.

     The swoop travels on `translate`, so the idle bob had to move off this
     element and onto the image inside it; two animations cannot share one
     property. --tr-dir is the side multiplier (-1 left, +1 right) and is
     always set, while --tr-dist is 0 unless the motion gate is on — so with
     motion off the whole expression collapses to zero and nothing is offset. */
  opacity: var(--tr-o, 1);
  translate: calc(var(--tr-dist, 0%) * var(--tr-dir, 0)) 0;
  scale: var(--tr-s, 1);
  rotate: calc(var(--rot, 0deg) * var(--tr-r, 0));
  transition:
    opacity   1000ms ease var(--d, 0ms),
    translate 1500ms cubic-bezier(.2, 1.1, .3, 1) var(--d, 0ms),
    scale     1500ms cubic-bezier(.2, 1.1, .3, 1) var(--d, 0ms),
    rotate    1500ms cubic-bezier(.2, 1.1, .3, 1) var(--d, 0ms);
}
.treat--left  { --tr-dir: -1; }
.treat--right { --tr-dir:  1; }
/* Anchored to the edges of the text column rather than the viewport, so a
   treat's inner edge always sits exactly 1rem clear of the words no matter
   how wide the window is. Anything that does not fit bleeds off the page
   and is clipped by the `overflow-x: clip` on body. */
.treat--left  { right: calc(100% - var(--pad) + 1rem); }
.treat--right { left:  calc(100% - var(--pad) + 1rem); }

/* Above 85rem there is enough margin for the treats to go properly big. */
@media (min-width: 85rem) {
  .treat { --treat-w: clamp(10rem, 12.5vw, 18rem); }
}

.treat img {
  width: 100%; height: auto; display: block;
}
.treat svg {
  width: 100%; height: auto;
  stroke: var(--ink);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  overflow: visible;
}

/* Fills, kept here so the whole set can be retinted in one place. */
.treat .t-dough  { fill: var(--t-dough); }
.treat .t-icing  { fill: var(--t-icing); }
.treat .t-hole   { fill: var(--cream); }
.treat .t-cheese { fill: var(--t-cheese); }
.treat .t-crust  { fill: var(--t-crust); }
.treat .t-sauce  { fill: var(--t-sauce); }
.treat .t-wrap   { fill: var(--ochre); }
.treat .t-sweet  { fill: var(--t-icing); }
.treat .t-shine  { stroke: var(--cream); stroke-width: 2.2; }
.treat .t-stick  { fill: var(--cream); }
.treat .t-pop-a  { fill: var(--t-icing); }
.treat .t-pop-b  { fill: var(--cream); }
.treat .t-al-a   { fill: var(--cream); }
.treat .t-al-b   { fill: var(--t-icing); }
.treat .t-sp     { stroke: none; }
.treat .t-sp-a   { fill: var(--cream); }
.treat .t-sp-b   { fill: var(--t-crust); }

/* Below 62rem there is no page gutter to sit in, so rather than hide the
   photographs entirely — which left phones with a wall of text and one
   doughnut — they drop into the flow as centred dividers between sections.
   Same artwork, same swoop, different job. */
@media (max-width: 61.99rem) {
  .treat {
    position: static;
    /* .treat is a <span>: absolute positioning blockified it, so going back
       to static returns it to display:inline, where width and margin:auto
       are simply ignored. It has to be told to be a block again. */
    display: block;
    width: min(44vw, 10rem);
    height: auto;
    margin: 3.5rem auto 0;
  }
  .treat img { width: 100%; height: auto; }
}

/* Same gate as the reveal system: hidden only once .motion is on,
   restored by .motion-fallback if the scripts never boot. */
/* Hidden state: well off to its own side of the page, tilted and slightly
   shrunk, so it swoops in across the margin rather than just fading up. */
html.motion { --tr-o: 0; --tr-s: .72; --tr-r: 1; --tr-dist: 165%; }
html.motion.motion-fallback:not(.motion-ready) {
  --tr-o: 1; --tr-s: 1; --tr-r: 0; --tr-dist: 0%;
}

html.motion .treat.pop {
  opacity: 1; translate: 0 0; scale: 1; rotate: 0deg;
}

/* The idle bob rides on the image inside, leaving `translate` on the
   treat itself free for the swoop. */
html.motion .treat.pop img,
html.motion .treat.pop svg {
  animation: treat-bob 12s ease-in-out 1900ms infinite;
}
@keyframes treat-bob {
  0%, 100% { translate: 0 0;      rotate: 0deg; }
  50%      { translate: 0 -18px;  rotate: 2deg; }
}

/* ------------------------------------------------------------ micro-interactions
   These are cheap, hover-only, and stay on even without the reveal script. */
.btn .arrow, .docs .doc-go {
  transition: transform 220ms cubic-bezier(.16, 1, .3, 1);
}
.btn:hover .arrow, .docs a:hover .doc-go { transform: translateX(4px); }

.nav a:not(.btn) { position: relative; }
.nav a:not(.btn)::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor;
  transform: scaleX(0); transform-origin: left center;
  transition: transform 280ms cubic-bezier(.16, 1, .3, 1);
}
.nav a:not(.btn):hover::after,
.nav a:not(.btn)[aria-current="page"]::after { transform: scaleX(1); }

/* The header rule only appears once you have left the top of the page. */
html.motion .site-header { border-bottom-color: transparent; transition: border-color 320ms ease; }
html.motion .site-header.scrolled { border-bottom-color: var(--ash); }

/* The FAQ marker turns from + into x rather than swapping glyphs. */
details.qa summary::after { transition: transform 280ms cubic-bezier(.16, 1, .3, 1); }
details.qa[open] summary::after { content: "+"; transform: rotate(45deg); }

/* Nothing moves without the motion class. This is the other half of the
   toggle: .motion turns the animations on, and its absence hard-stops every
   transition and animation on the page. */
html:not(.motion) { scroll-behavior: auto; }
html:not(.motion) *,
html:not(.motion) *::before,
html:not(.motion) *::after {
  transition: none !important;
  animation: none !important;
}

/* ------------------------------------------------------------ motion toggle
   Injected into the footer by nav.js. Present for everyone: some visitors
   want the animations their machine is suppressing, others want them off. */
.motion-toggle {
  font: inherit;
  font-size: 0.875rem;
  color: var(--ink-60);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--ash-2);
  padding: 0.25rem 0;
  cursor: pointer;
}
.motion-toggle:hover { color: var(--plum); border-bottom-color: var(--plum); }

/* ============================================================
   THE TYPEWRITER
   Set up by type.js on anything marked data-type. Every character
   is laid out from the first paint and merely hidden, so the line
   wraps identically from the first frame to the last and typing
   never moves the page.
   ============================================================ */

/* Restates the sentence for assistive tech, since the visible characters are
   aria-hidden. The 1px clipped box is the standard way to keep text in the
   accessibility tree while taking it out of the visual layout entirely. */
.tw-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tw-c {
  position: relative;
  visibility: hidden;
}
.tw-c.on { visibility: visible; }

/* The caret rides on the character currently being typed. `visibility` is
   inherited, so the pseudo-element has to switch itself back on to show
   through a character that is still hidden. */
.tw-live .tw-c.cur::before {
  content: "";
  visibility: visible;
  position: absolute;
  left: -0.04em; top: 0.1em; bottom: 0.14em;
  width: 0.055em;
  background: currentColor;
  animation: tw-blink 900ms steps(1, end) infinite;
}
@keyframes tw-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
