/*
  Joust website styles.

  Every colour, radius and font comes from the app's design system (Joust/App/DesignSystem,
  docs/09-DESIGN-SYSTEM.md): the pink, gold and silver palette and its roles, three radii,
  Aileron for text and Jost only for the JOUST wordmark. Buttons are opaque pills; the one control
  that floats over the page (the nav) uses the app's floating style. Gold that means something
  is metallic.

  The layout is editorial: large display type against small numbered labels, hairline rules in
  place of boxes, and lots of room.
*/

/* MARK: - Fonts: WOFF2, built by tools/make_fonts.py. Jost is cut down to the wordmark's five letters */

@font-face {
  font-family: "Aileron";
  src: url("../fonts/Aileron-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Aileron";
  src: url("../fonts/Aileron-SemiBold.woff2") format("woff2");
  font-weight: 500 600;
  font-display: swap;
}
@font-face {
  font-family: "Aileron";
  src: url("../fonts/Aileron-Bold.woff2") format("woff2");
  font-weight: 700 900;
  font-display: swap;
}
@font-face {
  font-family: "Jost";
  src: url("../fonts/Jost-Wordmark.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

/* MARK: - Tokens */

:root {
  /* Palette */
  --petal: #FFF4F7;
  --blush: #FBDDE6;
  --rose: #F2A7BD;
  --rose-deep: #E0708F;
  --raspberry: #C93468;
  --gold-light: #F1D891;
  --gold: #D4A84B;
  --gold-deep: #A87D2A;
  --silver-light: #ECEFF3;
  --silver: #C3C8D0;
  --silver-deep: #8A919C;
  --plum: #3A1E2C;

  /* Roles */
  --action: var(--raspberry);
  --success: #B8862B;
  --danger: #C62A3E;

  /* Surfaces */
  --surface: #FFF8FA;
  --surface-muted: #FBE6ED;
  --surface-raised: #FFFFFF;
  --surface-blush: #FBD9E4;
  --surface-success: rgba(212, 168, 75, 0.16);
  --surface-silver: #F1F2F5;
  --ink: #000000;
  --on-ink: #FFFFFF;

  /* Text */
  --text: #000000;
  --text-muted: rgba(0, 0, 0, 0.7);
  --text-faint: rgba(0, 0, 0, 0.5);
  --success-text: #8D6419;
  --silver-text: #5F6670;
  --link: var(--raspberry);

  /* Lines */
  --outline: rgba(0, 0, 0, 0.35);
  --outline-marked: #000000;
  --rule: rgba(0, 0, 0, 0.14);

  /* Metal (App/DesignSystem/Metal.swift) */
  --metal-bar: linear-gradient(180deg, #FFEDAD 0%, #E8C266 28%, #B38229 58%, #CC9E3D 82%, #F2D480 100%);
  --metal-text: linear-gradient(135deg, #F2D178 0%, #A87821 45%, #E0B554 62%, #9E6E1C 100%);
  --on-gold: #4A2E0D;

  /* Radius: three steps, nothing in between */
  --radius-small: 8px;
  --radius-card: 12px;
  --radius-large: 16px;

  /* Space */
  --space-xxs: 2px;
  --space-xs: 4px;
  --space-s: 8px;
  --space-m: 12px;
  --space-l: 16px;
  --space-xl: 24px;
  --space-xxl: 32px;
  --space-section: clamp(88px, 13vw, 176px);

  --page-width: 1320px;
  --reading-width: 720px;
  --margin: var(--space-l);

  /* Type: seven steps, each with its own tracking. Display tracking is worked out from the size
     where it's used (see .display), so it loosens as the type gets smaller */
  --text-label: 12px;
  --text-small: 14px;
  --text-body: 17px;
  --text-lede: clamp(18px, 1.6vw, 21px);
  --text-title: clamp(24px, 2.4vw, 32px);
  --text-headline: clamp(36px, 5.6vw, 80px);
  --text-display: clamp(52px, 10.4vw, 156px);
  --track-label: 0.08em;
  --track-small: 0.005em;
  --track-lede: -0.005em;
  --track-title: -0.025em;
  --track-headline: -0.04em;

  /* Motion: five durations and a few curves, so related things move alike */
  --dur-press: 120ms;    /* pressing down */
  --dur-quick: 200ms;    /* colour, opacity, small hover moves */
  --dur-move: 360ms;     /* things that change place */
  --dur-settle: 600ms;   /* springs */
  --dur-enter: 700ms;    /* content arriving */
  --stagger: 40ms;       /* between things arriving in turn */
  --stagger-dense: 10ms; /* between dots */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.55, 0, 1, 0.45);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  /* A spring that overshoots by about 7% and settles within --dur-settle. Browsers without
     linear() get this cubic instead; the real curve is set below */
  --spring: cubic-bezier(0.34, 1.36, 0.5, 1);
  /* Loops, which run on their own clocks */
  --loop-pulse: 2.4s;
  --loop-blink: 1.2s;
  --loop-bob: 1.8s;
  --loop-glint: 3.6s;
  --loop-ticker: 70s;

  /* Elevation: one level for things that float over the page, one for things that pop over them */
  --shadow-float: 0 1px 1px rgba(0, 0, 0, 0.05), 0 4px 14px rgba(0, 0, 0, 0.08);
  --shadow-pop: 0 2px 4px rgba(0, 0, 0, 0.06), 0 12px 32px rgba(0, 0, 0, 0.14);

  /* Dots that count places and players */
  --dot: 6px;
  --dot-gap: 3px;

  color-scheme: light dark;
}

/* The spring itself: stiffness 300, damping 22, sampled 40 times over --dur-settle */
@supports (transition-timing-function: linear(0, 1)) {
  :root { --spring: linear(0, 0.03, 0.107, 0.214, 0.335, 0.461, 0.582, 0.692, 0.79, 0.872, 0.938, 0.989, 1.027, 1.052, 1.067, 1.074, 1.075, 1.072, 1.065, 1.056, 1.047, 1.038, 1.029, 1.021, 1.014, 1.008, 1.003, 1, 0.997, 0.996, 0.995, 0.994, 0.994, 0.995, 0.995, 0.996, 0.997, 0.997, 0.998, 0.999, 1); }
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface: #160F12;
    --surface-muted: #2C1C23;
    --surface-raised: #35232B;
    --surface-blush: #4A2130;
    --surface-silver: #23202A;
    --ink: #FFFFFF;
    --on-ink: #000000;
    --text: #FFFFFF;
    --text-muted: rgba(255, 255, 255, 0.7);
    --text-faint: rgba(255, 255, 255, 0.5);
    --success-text: #F1D891;
    --silver-text: var(--silver);
    --link: var(--rose);
    --outline: rgba(255, 255, 255, 0.35);
    --outline-marked: #FFFFFF;
    --rule: rgba(255, 255, 255, 0.16);
    /* A shadow doesn't show on the dark page, so floating things get a hairline as well */
    --shadow-float: inset 0 0 0 1px var(--rule), 0 4px 14px rgba(0, 0, 0, 0.4);
    --shadow-pop: inset 0 0 0 1px var(--rule), 0 12px 32px rgba(0, 0, 0, 0.5);
  }
}

@media (min-width: 720px) {
  :root { --margin: var(--space-xl); }
}
@media (min-width: 1200px) {
  :root { --margin: var(--space-xxl); }
}

/* MARK: - Base */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 96px;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: "Aileron", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-size: var(--text-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  font-feature-settings: "kern", "liga", "calt";
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; height: auto; }

a { color: var(--link); text-underline-offset: 3px; text-decoration-thickness: 1px; }
@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration-thickness: 2px; }
}

::selection { background: var(--rose); color: #000; }

/* Focus is an outline only, so it follows each thing's own shape rather than changing it */
:focus-visible { outline: 2px solid var(--action); outline-offset: 3px; }

h1, h2, h3, h4 { margin: 0; font-weight: 700; text-wrap: balance; hanging-punctuation: first; }
p { margin: 0; text-wrap: pretty; }

.wrap { width: 100%; max-width: calc(var(--page-width) + var(--margin) * 2); margin: 0 auto; padding: 0 var(--margin); }

/* The type scale: display sizes for statements, small capital labels for everything around them */
.display { --size: var(--text-display); line-height: 0.9; }
/* Display sizes track tighter the bigger they get: -0.035em at 52px, -0.05em at 156px. Anything set
   at a display size gives its --size and shares the line */
.display, .role h3, .duel-big {
  font-size: var(--size);
  letter-spacing: calc(1.2px - 0.0575 * var(--size));
}
.headline {
  font-size: var(--text-headline);
  line-height: 0.96;
  letter-spacing: var(--track-headline);
}
.title {
  font-size: var(--text-title);
  line-height: 1.08;
  letter-spacing: var(--track-title);
}
.lede {
  font-size: var(--text-lede);
  line-height: 1.45;
  letter-spacing: var(--track-lede);
  color: var(--text-muted);
}
.label {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  line-height: 1.3;
}
.num { font-variant-numeric: tabular-nums; }
/* Numbering: one style everywhere. Small, raspberry, no brackets */
.section-head .label .num, .index-row .num, .column .num:not(.duel-big), .role li::before {
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  color: var(--action);
  font-variant-numeric: tabular-nums;
}

/* Press: everything you can click gives a little under your finger, then springs back. Each one
   lists transform in its own transition, on the spring */
:is(.button, .site-nav a, .logo, .status, .nav-toggle, .segmented button, .footer-grid a:not(.footer-mark), .footer-mark, .arrow-link, .knight.is-playable):active {
  transform: scale(0.97);
  transition-duration: var(--dur-press);
  transition-timing-function: var(--ease-out);
}
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.accent { color: var(--action); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--space-l); top: -60px; z-index: 100;
  background: var(--ink); color: var(--on-ink); padding: var(--space-s) var(--space-l);
  border-radius: 999px; text-decoration: none; font-weight: 600;
}
.skip-link:focus { top: var(--space-l); }

/* MARK: - Logo */

.logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-s);
  color: var(--text);
  text-decoration: none;
  transition: transform var(--dur-settle) var(--spring);
}
.logo img { width: 28px; height: 28px; }
/* The wordmark keeps its own size and tracking: it's the logo, not a step on the type scale */
.wordmark {
  font-family: "Jost", "Aileron", sans-serif;
  font-weight: 600;
  font-size: 21px;
  letter-spacing: -0.03em;
  line-height: 1;
}

/* MARK: - Header: a floating pill, the app's floatingButton style */

.site-header {
  position: fixed;
  top: var(--space-m);
  left: 0;
  right: 0;
  z-index: 50;
  pointer-events: none;
}
.site-header .wrap { display: flex; justify-content: space-between; align-items: center; gap: var(--space-m); }
/* The top inch of the page fades into the background behind the pill, so text scrolling up under it
   dissolves instead of being cut off. It comes in once the page leaves the top */
.site-header::before {
  content: "";
  position: absolute;
  top: calc(-1 * var(--space-m));
  left: 0;
  right: 0;
  height: 96px;
  background: linear-gradient(to bottom,
    var(--surface) 0%,
    color-mix(in srgb, var(--surface) 90%, transparent) 25%,
    color-mix(in srgb, var(--surface) 62%, transparent) 50%,
    color-mix(in srgb, var(--surface) 26%, transparent) 75%,
    transparent 100%);
  opacity: 0;
  transition: opacity var(--dur-quick) var(--ease-out);
}
.is-scrolling .site-header::before { opacity: 1; }

.pill-bar {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 6px 6px 6px var(--space-l);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  -webkit-backdrop-filter: saturate(1.6) blur(16px);
  backdrop-filter: saturate(1.6) blur(16px);
  box-shadow: var(--shadow-float);
  transition: box-shadow var(--dur-quick) var(--ease-out), background-color var(--dur-quick) var(--ease-out);
}
.pill-bar .logo { margin-right: var(--space-s); }
/* Over a coloured surface (the hero, a card, the bracket) the translucent pill turns into a smear, so
   it firms up and takes a hairline edge */
.is-over-colour .pill-bar {
  background-color: color-mix(in srgb, var(--surface) 95%, transparent);
  box-shadow: var(--shadow-float), inset 0 0 0 1px var(--rule);
}

.site-nav { display: flex; align-items: center; gap: var(--space-xxs); position: relative; }
.site-nav a {
  position: relative;
  z-index: 1;
  color: var(--text);
  text-decoration: none;
  font-size: var(--text-small);
  font-weight: 600;
  padding: var(--space-s) var(--space-m);
  border-radius: 999px;
  transition: color var(--dur-quick) var(--ease-out), background-color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
}
/* One blush pill behind the links that slides to whichever one you point at, and rests on the
   section you're reading */
.nav-indicator {
  position: absolute;
  left: 0;
  top: 50%;
  height: 34px;
  width: var(--w, 0);
  border-radius: 999px;
  background: var(--surface-muted);
  transform: translate(var(--x, 0), -50%);
  opacity: 0;
  transition: transform var(--dur-settle) var(--spring), width var(--dur-settle) var(--spring), opacity var(--dur-quick) var(--ease-out);
  pointer-events: none;
}
.nav-indicator.is-on { opacity: 1; }
/* 20px lines make the links 36px, the height of the button beside them, so the bar is 48px */
.site-nav a:not(.button) { line-height: 20px; }
.site-nav a[aria-current="page"] { color: var(--action); }
.site-nav a.button-filled { color: var(--on-ink); background: var(--ink); margin-left: var(--space-xs); }
@media (hover: hover) and (pointer: fine) {
  html:not(.js) .site-nav a:not(.button):hover { background: var(--surface-muted); }
  .site-nav a.button-filled:hover { background: color-mix(in srgb, var(--ink) 84%, var(--action)); }
}

/* A small status pill with a raspberry dot: coming soon */
.status {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-s);
  /* As tall as the nav pill beside it, so their edges line up as well as their centres */
  height: 48px;
  padding: 0 var(--space-l) 0 calc(var(--space-l) + 2px);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-float);
  font-size: var(--text-small);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: opacity var(--dur-move) var(--ease-out), transform var(--dur-move) var(--ease-out), filter var(--dur-move) var(--ease-out);
}
/* Once you're past the hero, the status pill tucks itself away, a little quicker than it comes back */
.is-scrolled .status {
  opacity: 0;
  transform: translateY(-12px) scale(0.96);
  filter: blur(4px);
  pointer-events: none;
  transition-duration: calc(var(--dur-move) * 0.75);
  transition-timing-function: var(--ease-in);
}
.dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--action);
  animation: pulse var(--loop-pulse) var(--ease-out) infinite;
  flex: none;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--action) 55%, transparent); }
  70%, 100% { box-shadow: 0 0 0 8px color-mix(in srgb, var(--action) 0%, transparent); }
}

.nav-toggle { display: none; }

@media (max-width: 860px) {
  .status { display: none; }
  .site-header .wrap { justify-content: center; }
  /* The pill itself grows down into the menu on the spring: closed it's one row, open it's as tall as
     its links (site.js measures them into --open-h) */
  .pill-bar {
    width: 100%;
    flex-wrap: wrap;
    justify-content: space-between;
    position: relative;
    height: 52px;
    overflow: hidden;
    border-radius: 26px;
    transition: height var(--dur-settle) var(--spring), border-radius var(--dur-settle) var(--spring), box-shadow var(--dur-quick) var(--ease-out), background-color var(--dur-quick) var(--ease-out);
  }
  .pill-bar.is-open { height: var(--open-h, auto); border-radius: 24px; background-color: color-mix(in srgb, var(--surface) 96%, transparent); box-shadow: var(--shadow-pop); }
  .nav-toggle {
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--ink);
    color: var(--on-ink);
    border: 0;
    cursor: pointer;
    padding: 0;
    transition: transform var(--dur-settle) var(--spring);
  }
  .nav-toggle svg { width: 16px; height: 16px; overflow: visible; }
  /* The two lines turn into a cross */
  .nav-toggle path { transform-box: view-box; transform-origin: 12px 12px; transition: transform var(--dur-settle) var(--spring); }
  .pill-bar.is-open .nav-toggle-top { transform: rotate(45deg) translateY(3px); }
  .pill-bar.is-open .nav-toggle-bottom { transform: rotate(-45deg) translateY(-3px); }
  .site-nav {
    order: 3;
    width: calc(100% + var(--space-l) - 6px);
    margin-left: calc(6px - var(--space-l));
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-s) 0 0;
    visibility: hidden;
    transition: visibility 0s var(--dur-settle);
  }
  .pill-bar.is-open .site-nav { visibility: visible; transition-delay: 0s; }
  /* The links come in one after another as it opens, and go together as it closes */
  .site-nav a {
    padding: var(--space-m) 10px;
    border-radius: var(--radius-card);
    font-size: var(--text-body);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity var(--dur-quick) var(--ease-in), transform var(--dur-quick) var(--ease-in), background-color var(--dur-quick) var(--ease-out);
  }
  .pill-bar.is-open .site-nav a {
    opacity: 1;
    transform: none;
    transition: opacity var(--dur-move) var(--ease-out), transform var(--dur-settle) var(--spring), background-color var(--dur-quick) var(--ease-out);
    transition-delay: calc(60ms + var(--i, 0) * var(--stagger)), calc(60ms + var(--i, 0) * var(--stagger)), 0s;
  }
  @media (hover: hover) and (pointer: fine) {
    .site-nav a:not(.button):hover { background: var(--surface-muted); }
  }
  .nav-indicator { display: none; }
  .site-nav a.button-filled { margin: var(--space-s) 0 0; text-align: center; justify-content: center; }
  /* The page doesn't scroll behind the open menu */
  html.menu-open { overflow: hidden; }
}

/* MARK: - Buttons: opaque pills. One filled call to action, an outlined one beside it */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-s);
  min-height: 48px;
  padding: var(--space-m) var(--space-xl);
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-body);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform var(--dur-settle) var(--spring), background-color var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out);
}
.button svg { width: 16px; height: 16px; flex: none; transition: transform var(--dur-quick) var(--ease-out); }

.button-filled { background: var(--ink); color: var(--on-ink); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 1px 2px rgba(0, 0, 0, 0.12); }
.button-outlined { background: var(--surface); color: var(--text); border-color: var(--outline); }
.button-small { min-height: 36px; padding: var(--space-s) var(--space-l); font-size: var(--text-small); }
@media (hover: hover) and (pointer: fine) {
  .button:hover svg { transform: translateX(3px); }
  .button-filled:hover { background: color-mix(in srgb, var(--ink) 84%, var(--action)); }
  .button-outlined:hover { border-color: var(--outline-marked); }
}

/* Metallic gold: a lit bar with a bright edge and a glint every few seconds */
.metal {
  position: relative;
  overflow: hidden;
  background: var(--metal-bar);
  color: var(--on-gold);
  border: 1px solid rgba(140, 97, 20, 0.6);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85);
}
.metal::after {
  content: "";
  position: absolute;
  inset: -50% auto -50% -40%;
  width: 28%;
  min-width: 40px;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0));
  transform: rotate(18deg);
  animation: glint var(--loop-glint) var(--ease-in-out) infinite;
  pointer-events: none;
}
@keyframes glint {
  0% { left: -40%; }
  25%, 100% { left: 130%; }
}
.metal-text {
  background: var(--metal-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* MARK: - Hero: the headline set into the sky of the tower scene */

.hero { padding-top: 84px; }
/* Along the bottom of the stage runs a strip of open ground for the count to stand on, clear of the
   knights' boots; the scene sits above it */
.hero-stage {
  --count-strip: calc(var(--space-l) * 2 + 32px);
  /* The scene's sky and grass (tools/make_art.py: HERO_SKY, HERO_GRASS) */
  --hero-sky-top: #9CCBF0;
  --hero-sky-horizon: #E1F0FB;
  --hero-grass: #97C98B;
  position: relative;
  border-radius: var(--radius-large);
  overflow: hidden;
  background: linear-gradient(to top, var(--hero-grass) var(--count-strip), var(--hero-sky-horizon) var(--count-strip));
  aspect-ratio: 16 / 10;
  container-type: inline-size;
  max-height: calc(100svh - 92px);
  min-height: 560px;
  width: 100%;
}
/* The scene keeps its 16:10 shape and covers the stage, held 64% of the way across. On a short,
   wide stage it crops at most 12% of its height, 80% of that from the sky above the flag and the
   rest from the ground under the front rank, so the princess and the knights' boots always show.
   Past that it stops growing and the sky and ground carry on to its left (--s is its width) */
.hero-art { position: absolute; inset: 0 0 var(--count-strip); container-type: size; isolation: isolate; }
.hero-scene {
  --s: clamp(160cqh, 100cqw, 181.8cqh);
  position: absolute;
  width: var(--s);
  aspect-ratio: 16 / 10;
  left: calc(min(0px, (100cqw - var(--s)) * 0.64) + max(0px, 100cqw - var(--s)));
  top: calc((100cqh - var(--s) * 0.625) * 0.8);
}
/* The sky and the ground beyond the scene's left edge: the art's gradient, down to where its hill
   meets that edge (tools/make_art.py: the ground is at 86% and the hill's end 1.68% under it) */
.hero-scene::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 100%;
  width: 100cqw;
  background: linear-gradient(var(--hero-sky-top), var(--hero-sky-horizon) 86%, var(--hero-sky-horizon) 87.68%, var(--hero-grass) 87.68%);
}
.hero-scene > picture, .hero-scene > picture img { position: absolute; inset: 0; width: 100%; height: 100%; }

/* The knights who've joined, one per filled place in the count. Each walks in from its own side of
   the tower and settles; leaving, it steps back out the same way */
.hero-crowd { position: absolute; inset: 0; }
.hero-knight {
  display: block;
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  height: auto;
  z-index: var(--z);
  opacity: 0;
  transform: translate(calc(var(--from) * 40%), 3%);
  transition: opacity var(--dur-quick) var(--ease-in), transform var(--dur-move) var(--ease-in);
}
.hero-knight.is-in {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-move) var(--ease-out), transform var(--dur-settle) var(--spring);
}
.hero-knight img { display: block; width: 100%; height: auto; }
/* Without the script, the twelve the count starts on are there */
html:not(.js) .hero-knight:nth-child(-n+12) { opacity: 1; transform: none; }
/* The copy runs from the stage's left edge to its middle, the middle of the page, and the headline is
   sized so its longer line, "love's castle.", ends right there. That line is 5.268em plus 16.8px of
   tracking wide, less the 0.085em the headline is pulled back by (Aileron Bold, measured) */
.hero-copy {
  --pad: clamp(var(--space-xl), 5vw, 72px);
  position: relative;
  z-index: 1;
  display: grid;
  gap: var(--space-xl);
  justify-items: start;
  padding: var(--pad);
  max-width: calc(50cqw + var(--pad));
  color: #000;
}
.hero-copy .display { --size: calc((50cqw - var(--pad) - 16.8px) / 5.183); }
.hero-copy .lede { color: rgba(0, 0, 0, 0.72); max-width: 26ch; }
.hero-copy .label.accent { color: var(--raspberry); }
/* The M's stem sits 0.089em inside its box, so pull the headline back to line its ink up with the label */
.hero-copy .display { margin-left: -0.085em; }
.hero-copy .display > span { display: block; }
.hero-copy .button-outlined { background: #FFF8FA; color: #000; border-color: rgba(0, 0, 0, 0.35); }
@media (hover: hover) and (pointer: fine) {
  .hero-copy .button-outlined:hover { border-color: #000; }
}
.hero-copy .button-filled { background: #000; color: #fff; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--space-s); }

/* A live count in the corner: one dot per place, filled for the players in */
.hero-count {
  position: absolute;
  z-index: 1;
  right: var(--space-l);
  bottom: var(--space-l);
  display: flex;
  align-items: center;
  gap: var(--space-m);
  padding: var(--space-s) var(--space-l) var(--space-s) var(--space-m);
  border-radius: 999px;
  background: rgba(255, 248, 250, 0.78);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
  backdrop-filter: blur(10px) saturate(1.4);
  color: #000;
  /* The hero stays light in dark mode, so the pill keeps the light shadow */
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05), 0 4px 14px rgba(0, 0, 0, 0.08);
}
.hero-count-dots { display: grid; grid-template-columns: repeat(8, var(--dot)); gap: var(--dot-gap); }
.hero-count-dots i { width: var(--dot); height: var(--dot); border-radius: 50%; background: rgba(0, 0, 0, 0.16); transition: background-color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring); }
.hero-count-dots i.is-in { background: var(--raspberry); }
.hero-count-dots i.is-new { transform: scale(1.6); transition-duration: var(--dur-press); }
/* The two messages share one cell; the cell's width is set by the script and springs between them.
   Each message keeps its own width rather than stretching to the longer one's, so it can be measured */
.hero-count-text { display: inline-grid; overflow: hidden; white-space: nowrap; transition: width var(--dur-settle) var(--spring); }
.hero-count-state { grid-area: 1 / 1; justify-self: start; opacity: 0; transform: translateY(0.6em); transition: opacity var(--dur-quick) var(--ease-out), transform var(--dur-move) var(--ease-out); }
.hero-count-state.is-on { opacity: 1; transform: none; }
/* A number that rolls: the old one slides up and out as the new one comes up from below */
.roll { display: inline-grid; overflow: hidden; vertical-align: bottom; }
.roll .num { grid-area: 1 / 1; transition: transform var(--dur-move) var(--ease-out), opacity var(--dur-move) var(--ease-out); }
.roll .num.is-below { transform: translateY(100%); opacity: 0; transition: none; }
.roll .num.is-above { transform: translateY(-100%); opacity: 0; }

@media (max-width: 860px) {
  .hero-stage {
    aspect-ratio: auto;
    max-height: none;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* The scene already ends in a band of ground under the boots, so the count needs less strip */
    --count-strip: calc(var(--space-l) + 32px);
    padding-bottom: var(--count-strip);
    background: linear-gradient(to top, var(--hero-grass) var(--count-strip), var(--hero-sky-top) var(--count-strip));
  }
  /* Under the copy, the scene is cropped in on the tower and the front rank, its sky fading into the
     stage so there's no seam */
  .hero-art {
    position: relative;
    inset: auto;
    flex: none;
    order: 2;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(transparent, #000 14%);
    mask-image: linear-gradient(transparent, #000 14%);
  }
  /* 112% of the square's height, with the point 64% across the scene at 55% across the square */
  .hero-scene { --s: 179.2cqh; left: calc(55cqw - var(--s) * 0.64); top: auto; bottom: 0; }
  /* Here the copy sits above the scene and has the stage's full width */
  .hero-copy { max-width: none; padding: var(--space-xxl) var(--space-xl) 0; }
  .hero-copy .display { --size: clamp(56px, 7.2vw, 116px); }
  .hero-count { right: auto; left: var(--space-l); }
}
@media (max-width: 520px) {
  .hero-actions { display: grid; grid-template-columns: 1fr; width: 100%; }
  /* Small enough on narrow phones that "love's castle." stays on one line */
  .hero-copy .display { --size: min(56px, 12vw); }
}

/* MARK: - Ticker: challenge prompts running past, like the app's sign board */

.ticker {
  margin-top: clamp(48px, 7vw, 96px);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  overflow: hidden;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: stretch;
}
.ticker-label {
  display: flex;
  align-items: center;
  padding: 0 var(--margin);
  border-right: 1px solid var(--rule);
  background: var(--surface);
  position: relative;
  z-index: 1;
  white-space: nowrap;
}
.ticker-window {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 80px, #000 calc(100% - 80px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 80px, #000 calc(100% - 80px), transparent);
}
.ticker-track {
  display: flex;
  width: max-content;
  animation: ticker var(--loop-ticker) linear infinite;
}
/* With the script, the track runs at a set speed in pixels a second instead, and eases to a stop
   under the pointer rather than freezing */
.js .ticker-track.is-driven { animation: none; }
@media (hover: hover) and (pointer: fine) {
  html:not(.js) .ticker:hover .ticker-track { animation-play-state: paused; }
}
.ticker-list {
  display: flex;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}
.ticker-list li {
  display: flex;
  align-items: center;
  gap: var(--space-xl);
  padding: var(--space-l) 0 var(--space-l) var(--space-xl);
  font-size: var(--text-title);
  letter-spacing: var(--track-title);
  white-space: nowrap;
}
.ticker-list li::after {
  content: "";
  width: 18px;
  height: 16px;
  background: var(--action);
  -webkit-mask: url("../art/heart.svg") center / contain no-repeat;
  mask: url("../art/heart.svg") center / contain no-repeat;
}
@keyframes ticker {
  to { transform: translateX(-50%); }
}
@media (max-width: 620px) {
  .ticker { grid-template-columns: 1fr; }
  .ticker-label { border-right: 0; border-bottom: 1px solid var(--rule); padding: var(--space-m) var(--margin); }
}

/* MARK: - Sections */

.section { padding: var(--space-section) 0 0; }
/* On a page that opens with a page hero, the first section follows straight on */
.page-hero + .section-first { padding-top: 0; }

/* A section opens on a ruled line: a numbered label on the left, the statement on the right */
.section-head {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  gap: var(--space-xl);
  padding-top: var(--space-l);
  border-top: 1px solid var(--rule);
  margin-bottom: clamp(48px, 6vw, 88px);
  align-items: first baseline;
}
.section-head .label { display: flex; gap: var(--space-m); }
.section-head-body { display: grid; gap: var(--space-xl); }
.section-head-body .lede { max-width: 48ch; }

@media (max-width: 860px) {
  .section-head { grid-template-columns: 1fr; gap: var(--space-l); }
}

/* MARK: - How it works: an index of steps */

.index { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--rule); }
.index-row {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  gap: var(--space-xl);
  align-items: first baseline;
  padding: var(--space-xl) 0;
  border-top: 1px solid var(--rule);
}
.index-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 112px;
  gap: var(--space-xl);
  align-items: first baseline;
}
.index-art { align-self: start; }
.index-row .title { transition: transform var(--dur-settle) var(--spring); }
.index-row p { color: var(--text-muted); max-width: 42ch; }
.index-art {
  width: 112px;
  height: 112px;
  border-radius: var(--radius-card);
  background: var(--surface-muted);
  display: grid;
  place-items: center;
  transition: transform var(--dur-settle) var(--spring), background-color var(--dur-quick) var(--ease-out);
}
.index-art img { width: 84%; }
@media (hover: hover) and (pointer: fine) {
  .index-row:hover .title { transform: translateX(6px); }
  .index-row:hover .index-art { transform: rotate(-4deg) scale(1.04); background: var(--surface-blush); }
}

@media (max-width: 960px) {
  .index-row { grid-template-columns: 1fr; gap: var(--space-s); }
  .index-body { grid-template-columns: 1fr 96px; grid-template-areas: "title art" "text art"; row-gap: var(--space-s); align-items: start; }
  .index-row .title { grid-area: title; }
  .index-row p { grid-area: text; }
  .index-art { grid-area: art; width: 96px; height: 96px; }
}
@media (max-width: 520px) {
  .index-body { grid-template-areas: "title art" "text text"; }
}

/* MARK: - Roles: two tall panels, the host in gold and pink, the player in silver */

/* The two cards share their rows (label, title, list), so both lists start at the same height. The
   list row takes the spare height, and the figure stands in the room below it */
.roles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto auto 1fr; gap: 0 var(--space-m); }
.role {
  --figure: clamp(150px, 15vw, 210px);
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-large);
  padding: clamp(var(--space-xl), 3vw, 48px);
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  gap: var(--space-xxl);
  align-content: start;
  min-height: 640px;
}
.role-host .label { color: var(--success-text); }
.role-player .label { color: var(--silver-text); }
.role-host { background: linear-gradient(170deg, var(--surface-blush) 0%, color-mix(in srgb, var(--gold-light) 45%, var(--surface-blush)) 100%); }
.role-player { background: linear-gradient(170deg, var(--surface-silver) 0%, color-mix(in srgb, var(--silver) 40%, var(--surface-silver)) 100%); }
.role h3 { --size: clamp(56px, 7vw, 104px); line-height: 0.9; }
.role .lede { max-width: 26ch; margin-top: var(--space-l); }
.role-figure {
  position: absolute;
  right: clamp(8px, 2vw, 32px);
  bottom: 0;
  width: var(--figure);
  pointer-events: none;
}
.role ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  align-self: start;
  /* Keep clear of the figure, which sits closer to the edge than the card's padding */
  max-width: calc(100% - var(--figure) - var(--space-s));
  padding-bottom: var(--space-xxl);
  counter-reset: role;
}
.role li {
  counter-increment: role;
  display: grid;
  grid-template-columns: 32px 1fr;
  align-items: baseline;
  gap: var(--space-s);
  padding: var(--space-m) 0;
  border-top: 1px solid var(--rule);
  font-size: var(--text-body);
}
.role li::before { content: counter(role, decimal-leading-zero); }

@media (max-width: 860px) {
  .roles { grid-template-columns: 1fr; grid-template-rows: none; gap: var(--space-m); }
  .role { min-height: 0; grid-row: auto; grid-template-rows: none; }
  .role ol { max-width: 100%; }
  .role-figure { width: 96px; top: var(--space-xl); bottom: auto; right: var(--space-xl); }
}

/* MARK: - Bracket: a game of two brackets that share one field of knights. Mia's runs left, the
   visitor's runs right, and a knight stays in while either host keeps them */

.duel {
  --row: clamp(40px, 5.4vw, 68px);
  --token: clamp(22px, 2.9vw, 38px);
  --field: clamp(64px, 11vw, 148px);
  margin: 0;
  border-radius: var(--radius-large);
  padding: clamp(var(--space-l), 3.2vw, 48px);
  /* A greyish blue, paler at the top, so the pink and gold of the brackets stand out on it */
  --duel-top: #EAF0F6;
  --duel-bottom: #D2DEEA;
  --duel-dot: color-mix(in srgb, #6F8CAB 30%, transparent);
  background:
    radial-gradient(circle, var(--duel-dot) 1px, transparent 1.6px) 0 0 / 16px 16px,
    linear-gradient(170deg, var(--duel-top), var(--duel-bottom));
}
@media (prefers-color-scheme: dark) {
  .duel { --duel-top: #1C232D; --duel-bottom: #141A22; --duel-dot: color-mix(in srgb, #8FA8C4 22%, transparent); }
}

.duel-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--field) minmax(0, 1fr);
  align-items: center;
  gap: var(--space-s);
}
.duel-host {
  display: inline-flex;
  align-items: center;
  gap: var(--space-s);
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}
.duel-host i { width: var(--dot); height: var(--dot); border-radius: 50%; flex: none; }
.duel-host-mia { justify-self: start; }
.duel-busy { color: var(--action); }
.duel-busy[hidden] { display: none; }
/* While Mia judges, her dot pulses like the status dot */
.duel-host-mia:has(.duel-busy:not([hidden])) i { animation: pulse var(--loop-pulse) var(--ease-out) infinite; }
@keyframes blink { 50% { opacity: 0.35; } }
.duel-host-mia i { background: var(--raspberry); }
.duel-host-field { justify-self: center; text-align: center; }
.duel-host-you { justify-self: end; }
.duel-host-you i { background: var(--metal-text); }

.duel-board {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) var(--field) repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(8, var(--row));
  gap: 0 var(--space-s);
  margin: var(--space-xl) 0;
}
.duel-fallback { display: none; }
/* The lists: a pale strip down the middle where the field of knights waits */
.duel-list { grid-column: 4; grid-row: 1 / -1; margin: calc(var(--space-s) * -1) 0; border-radius: 999px; background: var(--surface); }
.duel-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.duel-lines path { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: stroke var(--dur-quick) var(--ease-out), opacity var(--dur-quick) var(--ease-out); }
.duel-lines .is-open { stroke: var(--outline); stroke-width: 1.5; stroke-dasharray: 0 7; opacity: 0.7; }
/* The dots are lighter against the dark page, so they keep their full weight there */
@media (prefers-color-scheme: dark) {
  .duel-lines .is-open { stroke-width: 2; opacity: 1; }
  .duel-heart path { stroke-width: 2; }
}
.duel-lines .is-lost { stroke: var(--silver-deep); opacity: 0.45; }
.duel-lines .is-won { stroke-width: 3.5; }
.duel-lines .is-won-mia { stroke: var(--raspberry); }
.duel-lines .is-won-you { stroke: url(#duel-gold); }
.duel-lines .is-drawing { transition: stroke-dashoffset var(--dur-move) var(--ease-in-out); }

.duel-slot { position: relative; z-index: 1; display: grid; place-items: center; min-width: 0; }
.duel-empty { width: 10px; height: 10px; border-radius: 50%; border: 1.5px dashed var(--outline); }

/* A knight: a shield carrying their own device */
.knight {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  cursor: default;
  border-radius: var(--radius-small);
  -webkit-tap-highlight-color: transparent;
  transition: transform var(--dur-settle) var(--spring);
}
.knight[aria-disabled="true"] { cursor: default; }
.knight-shield {
  display: block;
  width: var(--token);
  height: calc(var(--token) * 1.15);
  overflow: visible;
  transition: transform var(--dur-settle) var(--spring), opacity var(--dur-move) var(--ease-out), filter var(--dur-move) var(--ease-out);
}
.knight-rim { fill: none; stroke: var(--text); stroke-opacity: 0.7; stroke-width: 1.6; }
.knight-name { font-size: var(--text-label); font-weight: 600; line-height: 1; transition: opacity var(--dur-quick) var(--ease-out), color var(--dur-quick) var(--ease-out); }

/* Pick me: playable knights bob in turn and lift when you point at them */
.knight.is-playable { cursor: pointer; }
.knight.is-playable .knight-shield { animation: bob var(--loop-bob) var(--ease-in-out) infinite; animation-delay: calc(var(--i, 0) * var(--loop-bob) / -8); filter: drop-shadow(0 3px 0 color-mix(in srgb, var(--gold) 70%, transparent)); }
.knight.is-playable:focus-visible .knight-shield { animation: none; transform: translateY(-4px) rotate(-5deg) scale(1.12); }
@media (hover: hover) and (pointer: fine) {
  .knight.is-playable:hover .knight-shield { animation: none; transform: translateY(-4px) rotate(-5deg) scale(1.12); }
}
.knight.is-rival .knight-shield { transform: rotate(4deg) scale(0.94); }
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}
/* Beaten in one bracket: knocked askew and greyed. Out of both: knocked flat */
.knight.is-beaten .knight-shield { transform: rotate(-12deg) translateY(2px); opacity: 0.4; filter: grayscale(1); transition-delay: var(--dur-move); }
.knight.is-out .knight-shield { transform: rotate(-78deg) translate(-2px, 6px) scale(0.86); opacity: 0.32; filter: grayscale(1); transition-delay: var(--dur-move); }
.knight.is-out .knight-name { opacity: 0.4; text-decoration: line-through; transition-delay: var(--dur-move); }
/* A pick lands as its line arrives */
.knight.is-new .knight-shield { animation: hop var(--dur-settle) var(--spring) var(--dur-move) both; }
@keyframes hop {
  0% { transform: translateY(10px) scale(0.3); opacity: 0; }
  100% { transform: none; opacity: 1; }
}

/* On the field, a pip either side says which hosts still have the knight */
.knight-field { grid-template-columns: 8px auto 8px; align-items: center; column-gap: clamp(4px, 0.8vw, 10px); }
.knight-field .knight-name { grid-column: 1 / -1; }
.knight-pip { width: 7px; height: 7px; border-radius: 50%; border: 1.5px solid var(--outline); transition: background-color var(--dur-quick) var(--ease-out), border-color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring); transition-delay: var(--dur-move); }
.knight-pip.is-on { border-color: transparent; transform: scale(1.15); }
.knight-pip-mia.is-on { background: var(--raspberry); }
.knight-pip-you.is-on { background: var(--gold); }
/* What each knight did in round one, shown above them when you point, focus or tap */
.knight-field[data-line]::after {
  content: attr(data-line);
  position: absolute;
  bottom: calc(100% + 2px);
  left: 50%;
  transform: translate(-50%, 4px);
  z-index: 3;
  padding: var(--space-xs) var(--space-s);
  border-radius: var(--radius-small);
  background: var(--ink);
  color: var(--on-ink);
  font-size: var(--text-label);
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-quick) var(--ease-out), transform var(--dur-quick) var(--ease-out), visibility 0s var(--dur-quick);
}
.knight-field[data-line].is-telling::after, .knight-field[data-line]:focus-visible::after { opacity: 1; visibility: visible; transform: translate(-50%, 0); transition-delay: 0s; }
@media (hover: hover) and (pointer: fine) {
  .knight-field[data-line]:hover::after { opacity: 1; visibility: visible; transform: translate(-50%, 0); transition-delay: 0s; }
}

/* The winner of each bracket sits on a heart */
.duel-slot-final .knight { gap: var(--space-s); }
.duel-slot-final .knight-shield { width: calc(var(--token) * 1.3); height: calc(var(--token) * 1.5); position: relative; z-index: 1; }
.duel-heart {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--token) * 2.6);
  height: calc(var(--token) * 2.3);
  transform: translate(-50%, -62%);
  overflow: visible;
}
.duel-heart path { fill: none; stroke: var(--outline); stroke-width: 1.5; stroke-dasharray: 0 5; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.duel-heart.is-won path { stroke: none; }
.duel-slot-final[data-side="mia"] .duel-heart.is-won path { fill: var(--rose); }
.duel-slot-final[data-side="you"] .duel-heart.is-won path { fill: url(#duel-gold-fill); }
.duel-heart.is-won { animation: beat var(--dur-settle) var(--spring) var(--dur-move) both; }
@keyframes beat {
  0% { transform: translate(-50%, -62%) scale(0.4); }
  100% { transform: translate(-50%, -62%) scale(1); }
}
.duel-final-label { position: absolute; top: calc(50% + var(--token) * 1.15); left: 50%; transform: translateX(-50%); display: grid; justify-items: center; gap: 2px; text-align: center; white-space: nowrap; }
.duel-final-label .label { color: var(--text-faint); }
.duel-final-label strong { font-size: var(--text-lede); letter-spacing: var(--track-lede); line-height: 1.1; }

.duel-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-l) var(--space-xl);
  padding-top: var(--space-l);
  border-top: 1px solid var(--rule);
}
.duel-note { font-size: var(--text-lede); letter-spacing: var(--track-lede); max-width: 52ch; min-height: 2.9em; display: flex; align-items: center; transition: opacity var(--dur-quick) var(--ease-out), filter var(--dur-quick) var(--ease-out); }
.duel-note.is-changing { opacity: 0; filter: blur(4px); }
.duel-meta { display: flex; align-items: center; gap: var(--space-l); }
/* Before the count, so the count keeps its place at the right while the button is hidden */
.duel-reset { order: -1; transition: opacity var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring), visibility 0s; }
.duel-reset.is-hidden { opacity: 0; transform: translateY(4px); visibility: hidden; transition: opacity var(--dur-quick) var(--ease-in), transform var(--dur-quick) var(--ease-in), visibility 0s var(--dur-quick); }
.duel-count { display: inline-flex; align-items: center; gap: var(--space-m); white-space: nowrap; }
.duel-dots { display: grid; grid-template-columns: repeat(8, var(--dot)); gap: var(--dot-gap); }
.duel-dots i { width: var(--dot); height: var(--dot); border-radius: 50%; background: var(--rule); transition: background-color var(--dur-quick) var(--ease-out); }
.duel-dots i.is-in { background: var(--action); }

/* Without JavaScript there's no game, so the static bracket shows instead */
html:not(.js) .duel-board { display: block; }
html:not(.js) .duel-fallback { display: block; margin: 0 auto; }
html:not(.js) .duel-head, html:not(.js) .duel-foot { display: none; }

/* The rules, as three big numbers */
.duel-rules { margin-top: clamp(48px, 6vw, 88px); }
.duel-rules .column { gap: var(--space-s); }
.duel-rules .column .duel-big { --size: clamp(72px, 9vw, 136px); line-height: 0.82; font-weight: 700; color: var(--text); margin-bottom: var(--space-s); }
.duel-rules .column:nth-child(3) .duel-big { background: var(--metal-text); -webkit-background-clip: text; background-clip: text; color: transparent; }

@media (max-width: 720px) {
  /* Rows tall enough for a shield and its name on the label step */
  .duel { --row: 48px; --token: 20px; --field: 68px; }
  .duel-host-field { display: none; }
  .duel-head { grid-template-columns: 1fr 1fr; }
  .duel-board { gap: 0 var(--space-xs); }
  .knight-field { column-gap: 3px; grid-template-columns: 6px auto 6px; }
  .knight-pip { width: 6px; height: 6px; }
  .duel-final-label .label { display: none; }
  .duel-meta { width: 100%; justify-content: space-between; }
}

/* MARK: - Presets: a ruled table */

.table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.table th {
  text-align: left;
  padding: 0 var(--space-l) var(--space-m) 0;
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--text-faint);
  border-bottom: 1px solid var(--rule);
}
.table td {
  padding: var(--space-l) var(--space-l) var(--space-l) 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--text-body);
  vertical-align: baseline;
}
.table td:first-child { font-size: var(--text-title); font-weight: 700; letter-spacing: var(--track-title); width: 28%; }
/* One dot per player place, in rows of eight, lighting up in turn when you point at the row */
.seats { display: inline-grid; grid-template-columns: 2.4ch auto; align-items: center; gap: var(--space-s); height: 1lh; }
.seat-grid { display: grid; grid-template-columns: repeat(8, var(--dot)); gap: var(--dot-gap); }
.seat-grid i {
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: var(--outline);
  transition: background-color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
  transition-delay: calc(var(--i) * var(--stagger-dense));
}
/* The rows rise in on their own transition, so pointing dims the other rows' cells instead */
.table tbody td { transition: opacity var(--dur-quick) var(--ease-out), color var(--dur-quick) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .table tbody:hover tr:not(:hover) td { opacity: 0.45; }
  .table tbody tr:hover td:first-child { color: var(--action); }
  .table tbody tr:hover .seat-grid i { background: var(--action); transform: scale(1.15); }
}

@media (max-width: 720px) {
  .table thead { display: none; }
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); padding: var(--space-l) 0; border-bottom: 1px solid var(--rule); column-gap: var(--space-l); }
  .table td { border: 0; padding: var(--space-xs) 0; font-size: var(--text-small); display: flex; justify-content: space-between; gap: var(--space-s); }
  .table td::before { content: attr(data-label); color: var(--text-faint); }
  .table td:first-child { grid-column: 1 / -1; width: auto; margin-bottom: var(--space-s); }
  .table td:first-child::before { content: none; }
  .seat-grid { display: none; }
}

.timing {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  gap: var(--space-xl);
  margin-top: clamp(48px, 6vw, 88px);
  padding-top: var(--space-l);
  border-top: 1px solid var(--rule);
  align-items: first baseline;
}
.timing-body { display: grid; gap: var(--space-l); }
.timing-body p { max-width: 56ch; }
/* The answer times as a segmented control: a thumb that springs between them */
.segmented {
  position: relative;
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  padding: 4px;
  border-radius: 999px;
  background: var(--surface-muted);
  justify-self: start;
}
.segmented button {
  position: relative;
  z-index: 1;
  font: inherit;
  font-size: var(--text-small);
  font-weight: 600;
  padding: var(--space-s) var(--space-l);
  min-width: 92px;
  border: 0;
  background: none;
  color: var(--text-muted);
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
}
.segmented button[aria-checked="true"] { color: var(--on-ink); }
.segmented-thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: var(--w, 0);
  transform: translateX(var(--x, 4px));
  border-radius: 999px;
  background: var(--ink);
  transition: transform var(--dur-settle) var(--spring), width var(--dur-settle) var(--spring);
}
html:not(.js) .segmented button[aria-checked="true"] { background: var(--ink); }
/* site.js sets min-height to the tallest note, so changing it never moves the small print */
.timing-note { font-size: var(--text-lede); letter-spacing: var(--track-lede); max-width: 44ch; transition: opacity var(--dur-quick) var(--ease-out), filter var(--dur-quick) var(--ease-out); }
.timing-note.is-changing { opacity: 0; filter: blur(4px); }
.timing-small { font-size: var(--text-small); }
@media (max-width: 520px) {
  .segmented { justify-self: stretch; }
  .segmented button { min-width: 0; padding: var(--space-s) var(--space-xs); }
}
@media (max-width: 860px) { .timing { grid-template-columns: 1fr; gap: var(--space-l); } }

/* MARK: - Safety: three columns between hairlines */

.columns { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--rule); }
.column { display: grid; gap: var(--space-m); align-content: start; padding: var(--space-xl) var(--space-xl) var(--space-xl) 0; }
.column + .column { padding-left: var(--space-xl); border-left: 1px solid var(--rule); }
.column p { color: var(--text-muted); }
@media (max-width: 860px) {
  .columns { grid-template-columns: 1fr; }
  .column, .column + .column { padding: var(--space-xl) 0; border-left: 0; }
  .column + .column { border-top: 1px solid var(--rule); }
}

/* State dating-safety laws ask for this in bold capitals of at least 12pt */
.notice {
  font-weight: 700;
  text-transform: uppercase;
  font-size: var(--text-body);
  letter-spacing: var(--track-small);
  line-height: 1.4;
  padding: var(--space-xl);
  border-radius: var(--radius-card);
  background: var(--surface-silver);
  margin-top: var(--space-xl);
  max-width: calc(70ch + var(--space-xl) * 2);
  text-wrap: balance;
}
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-s);
  margin-top: var(--space-xl);
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  transition: color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
}
.arrow-link svg { width: 14px; height: 14px; transition: transform var(--dur-quick) var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .arrow-link:hover { color: var(--action); }
  .arrow-link:hover svg { transform: translateX(3px); }
}

/* MARK: - Closing call to action */

.closing {
  border-radius: var(--radius-large);
  background:
    radial-gradient(120% 90% at 100% 100%, color-mix(in srgb, var(--rose) 55%, transparent), transparent 60%),
    linear-gradient(140deg, var(--raspberry), var(--rose-deep));
  color: #fff;
  padding: clamp(var(--space-xxl), 7vw, 104px) clamp(var(--space-xl), 6vw, 88px);
  display: grid;
  gap: var(--space-xl);
  justify-items: start;
  position: relative;
  overflow: hidden;
}
.closing .lede { color: rgba(255, 255, 255, 0.9); max-width: 36ch; }
.closing .label { color: rgba(255, 255, 255, 0.8); }
.closing h2 { position: relative; }
.closing .button-filled { background: #fff; color: #000; }
@media (hover: hover) and (pointer: fine) {
  .closing .button-filled:hover { background: var(--petal); }
}
.closing-mark {
  position: absolute;
  right: -2%;
  bottom: -14%;
  width: clamp(220px, 32vw, 440px);
  aspect-ratio: 1;
  background: #fff;
  opacity: 0.14;
  -webkit-mask: url("../art/mark.svg") center / contain no-repeat;
  mask: url("../art/mark.svg") center / contain no-repeat;
  pointer-events: none;
}

/* The waitlist: an email field and the button in one white pill. Sending swaps the button's label
   for three dots; once it's in, the pill gives way to a heart that fills */
.waitlist { display: grid; width: min(100%, 540px); position: relative; z-index: 1; }
.waitlist-fallback { display: none; }
html:not(.js) .waitlist { display: none; }
html:not(.js) .waitlist-fallback { display: inline-flex; }
.waitlist-field, .waitlist-done { grid-area: 1 / 1; }
.waitlist-field {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 4px 4px 4px var(--space-xl);
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05), 0 6px 20px rgba(90, 10, 40, 0.18);
  transition: opacity var(--dur-quick) var(--ease-in), transform var(--dur-quick) var(--ease-in), box-shadow var(--dur-quick) var(--ease-out);
}
.waitlist-field:focus-within { box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.55), 0 6px 20px rgba(90, 10, 40, 0.18); }
.waitlist-input {
  flex: 1;
  min-width: 0;
  height: 48px;
  border: 0;
  background: none;
  color: #000;
  font: inherit;
  font-size: var(--text-body);
  outline: none;
}
.waitlist-input::placeholder { color: rgba(0, 0, 0, 0.45); }
.closing .waitlist-submit { background: #000; color: #fff; position: relative; flex: none; }
.waitlist-submit-label { display: inline-flex; align-items: center; gap: var(--space-s); transition: opacity var(--dur-quick) var(--ease-out); }
.waitlist-spinner { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 5px; opacity: 0; transition: opacity var(--dur-quick) var(--ease-out); }
.waitlist-spinner i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; animation: blink var(--loop-blink) var(--ease-in-out) infinite; }
.waitlist-spinner i:nth-child(2) { animation-delay: calc(var(--loop-blink) / 6); }
.waitlist-spinner i:nth-child(3) { animation-delay: calc(var(--loop-blink) / 3); }
.waitlist.is-sending .waitlist-submit-label { opacity: 0; }
.waitlist.is-sending .waitlist-spinner { opacity: 1; }
.waitlist.is-sending .waitlist-submit { cursor: progress; }
@media (hover: hover) and (pointer: fine) {
  .closing .waitlist-submit:hover { background: color-mix(in srgb, #000 84%, var(--raspberry)); }
}
.waitlist.is-invalid .waitlist-field { box-shadow: 0 0 0 3px #fff, 0 6px 20px rgba(90, 10, 40, 0.18); animation: nudge var(--dur-move) var(--ease-out); }
@keyframes nudge {
  20% { transform: translateX(-6px); }
  45% { transform: translateX(5px); }
  70% { transform: translateX(-3px); }
}
.waitlist-message { min-height: 1.5em; margin-top: var(--space-s); padding-left: var(--space-xl); font-size: var(--text-small); color: #fff; }
.waitlist-done {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  min-height: 56px;
  font-size: var(--text-body);
  visibility: hidden;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur-enter) var(--ease-out), transform var(--dur-enter) var(--ease-out), visibility 0s var(--dur-enter);
}
.waitlist-done p { max-width: 40ch; }
.waitlist-heart { width: 44px; height: 44px; flex: none; overflow: visible; }
.waitlist-heart-rim { fill: none; stroke: #fff; stroke-width: 2; }
.waitlist-heart-fill { fill: #fff; transform: translateY(100%); transition: transform var(--dur-settle) var(--ease-in-out) var(--dur-quick); }
.waitlist.is-done .waitlist-field { opacity: 0; transform: scale(0.96); visibility: hidden; transition: opacity var(--dur-quick) var(--ease-in), transform var(--dur-quick) var(--ease-in), visibility 0s var(--dur-quick); }
.waitlist.is-done .waitlist-done { visibility: visible; opacity: 1; transform: none; transition-delay: var(--dur-quick); transition-property: opacity, transform; }
.waitlist.is-done .waitlist-heart-fill { transform: none; }
.waitlist.is-done .waitlist-heart { animation: beat-once var(--dur-settle) var(--spring) calc(var(--dur-quick) + var(--dur-settle)) both; }
@keyframes beat-once {
  0% { transform: scale(1); }
  40% { transform: scale(1.18); }
  100% { transform: scale(1); }
}
@media (max-width: 520px) {
  .waitlist-field { flex-direction: column; align-items: stretch; padding: 4px; border-radius: 28px; }
  .waitlist-input { flex: none; padding: 0 var(--space-l); }
  .waitlist-message { padding-left: var(--space-l); }
}

/* MARK: - Long-form pages: terms, privacy, safety, contact */

.page-hero { padding: clamp(120px, 15vw, 176px) 0 clamp(48px, 6vw, 80px); }
.page-hero .wrap { display: grid; gap: var(--space-xl); justify-items: start; }
.page-hero .lede { max-width: 44ch; }

.draft-banner {
  display: flex;
  gap: var(--space-m);
  align-items: flex-start;
  padding: var(--space-l);
  border-radius: var(--radius-card);
  background: var(--surface-success);
  font-size: var(--text-small);
  max-width: 720px;
}
.draft-banner strong { color: var(--success-text); }
.draft-banner svg { width: 20px; height: 20px; flex: none; color: var(--success); margin-top: 2px; }

.doc .wrap {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
  gap: var(--space-xl);
  align-items: start;
}
.doc-inner { display: contents; }
.toc {
  position: sticky;
  top: 96px;
  max-height: calc(100vh - 120px);
  overflow: auto;
  font-size: var(--text-small);
  padding: var(--space-l) var(--space-s) 0 0;
  border-top: 1px solid var(--rule);
}
.toc p { margin-bottom: var(--space-m); color: var(--text-faint); }
.toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-xxs); }
.toc a {
  display: block;
  color: var(--text-muted);
  text-decoration: none;
  padding: var(--space-xs) 0;
  transition: color var(--dur-quick) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .toc a:hover { color: var(--action); }
}
/* Where you are: a raspberry marker on a hairline track slides to the section you're reading */
.js .toc ol { position: relative; padding-left: var(--space-m); }
.js .toc ol::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 1px; background: var(--rule); }
.toc-marker {
  position: absolute;
  left: -0.5px;
  top: 0;
  width: 2px;
  height: var(--h, 0);
  border-radius: 1px;
  background: var(--action);
  transform: translateY(var(--y, 0));
  opacity: 0;
  transition: transform var(--dur-settle) var(--spring), height var(--dur-settle) var(--spring), opacity var(--dur-quick) var(--ease-out);
}
.toc-marker.is-on { opacity: 1; }
.toc a[aria-current="location"] { color: var(--text); }
/* The phone's collapsible row; site.js adds it */
.toc-toggle { display: none; }

.prose { max-width: var(--reading-width); padding-top: var(--space-l); border-top: 1px solid var(--rule); }
.prose h2 {
  font-size: var(--text-title);
  line-height: 1.1;
  letter-spacing: var(--track-title);
  margin: clamp(64px, 8vw, 104px) 0 var(--space-l);
}
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: var(--text-lede); letter-spacing: var(--track-lede); margin: var(--space-xxl) 0 var(--space-m); }
.prose p, .prose ul, .prose ol { margin: 0 0 var(--space-l); }
.prose ul, .prose ol { padding-left: var(--space-xl); }
.prose li { margin-bottom: var(--space-s); }
.prose li::marker { color: var(--action); }
.prose .caps { font-size: var(--text-body); }
.prose table { width: 100%; border-collapse: collapse; margin: 0 0 var(--space-l); font-size: var(--text-small); }
.prose th, .prose td { text-align: left; padding: var(--space-s) var(--space-m) var(--space-s) 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
.prose th { font-size: var(--text-label); font-weight: 600; letter-spacing: var(--track-label); text-transform: uppercase; color: var(--text-faint); }
.table-scroll { overflow-x: auto; }

@media (max-width: 860px) {
  .doc .wrap { grid-template-columns: 1fr; }
  .toc { position: static; max-height: none; padding-bottom: var(--space-xl); }
  .toc ol { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); column-gap: var(--space-xl); }
  /* On a phone the contents fold into one row between hairlines, opening on the spring */
  .js .toc { padding: 0; border-bottom: 1px solid var(--rule); margin-bottom: var(--space-xl); overflow: visible; }
  .js .toc > p { display: none; }
  .js .toc-toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: var(--space-l) 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-small);
    font-weight: 600;
    color: var(--text);
    text-align: left;
    cursor: pointer;
  }
  .toc-toggle svg { width: 16px; height: 16px; flex: none; transition: transform var(--dur-settle) var(--spring); }
  .toc.is-open .toc-toggle svg { transform: rotate(180deg); }
  .js .toc ol {
    padding-left: 0;
    height: 0;
    overflow: hidden;
    visibility: hidden;
    transition: height var(--dur-settle) var(--spring), visibility 0s var(--dur-settle);
  }
  .js .toc.is-open ol { height: var(--toc-h, auto); visibility: visible; transition-delay: 0s; }
  .js .toc li:last-child { padding-bottom: var(--space-m); }
  .js .toc ol::before, .toc-marker { display: none; }
}

/* Placeholders still to fill in before launch */
.todo {
  background: var(--surface-success);
  color: var(--success-text);
  border-radius: 4px;
  padding: 0 4px;
  font-weight: 600;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Contact: a ruled index of addresses */
.contact-list { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid var(--rule); }
.contact-list li {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 5fr) minmax(0, 4fr);
  gap: var(--space-xl);
  padding: var(--space-xl) 0;
  border-top: 1px solid var(--rule);
  align-items: baseline;
}
.contact-list h2 { font-size: var(--text-title); line-height: 1.1; letter-spacing: var(--track-title); }
.contact-list p { color: var(--text-muted); }
.contact-line { font-weight: 600; word-break: break-word; }
@media (max-width: 860px) {
  .contact-list li { grid-template-columns: 1fr; gap: var(--space-s); }
}

/* MARK: - Footer, with the wordmark across the whole width */

.site-footer {
  /* Sized so the wordmark's ink runs the width of the page, from the J's tail to the T's right edge:
     2.845em in Jost SemiBold at the wordmark's tracking */
  --wordmark-size: min(calc((100vw - var(--margin) * 2) / 2.845), calc(var(--page-width) / 2.845));
  position: relative;
  isolation: isolate;
  padding: var(--space-section) 0 0;
  overflow: hidden;
}
/* A blush fade rising from the bottom edge, behind the wordmark */
.site-footer::before {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: -1;
  height: calc(var(--wordmark-size) * 1.4);
  background: linear-gradient(to top, var(--surface-blush), color-mix(in srgb, var(--surface-blush) 40%, transparent) 50%, transparent);
  pointer-events: none;
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(0, 6fr) repeat(3, minmax(0, 2fr));
  gap: var(--space-xl);
  padding-top: var(--space-l);
  border-top: 1px solid var(--rule);
  font-size: var(--text-small);
}
/* Every column opens on a 28px row: the logo's silhouette in the first, a label sitting on the
   row's foot in the rest, so what's under them starts on one line */
.footer-grid .label { color: var(--text-faint); margin-bottom: var(--space-m); height: 28px; display: flex; align-items: flex-end; }
.footer-grid .footer-mark {
  display: block;
  width: 28px;
  height: 28px;
  margin-bottom: var(--space-m);
  background: var(--text);
  -webkit-mask: url("../art/mark.svg") center / contain no-repeat;
  mask: url("../art/mark.svg") center / contain no-repeat;
  transition: background-color var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
}
@media (hover: hover) and (pointer: fine) {
  .footer-grid .footer-mark:hover { background-color: var(--action); }
}
.footer-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-xs); }
.footer-grid a {
  display: inline-block;
  color: var(--text);
  text-decoration: none;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
  transition: color var(--dur-quick) var(--ease-out), background-size var(--dur-quick) var(--ease-out), transform var(--dur-settle) var(--spring);
}
@media (hover: hover) and (pointer: fine) {
  .footer-grid a:not(.footer-mark):hover { color: var(--action); background-size: 100% 1px; }
}
.footer-about { max-width: 30ch; color: var(--text-muted); }
.footer-big {
  display: block;
  font-family: "Jost", "Aileron", sans-serif;
  font-weight: 600;
  /* Runs the width of the page, sitting on the bottom edge */
  font-size: var(--wordmark-size);
  line-height: 0.72;
  /* Room for the J, which drops a quarter of an em below the line */
  padding-bottom: 0.26em;
  letter-spacing: -0.055em;
  /* The J's tail curls 0.147em left of where the letter starts, so the wordmark starts that far in,
     and the tail lines up with the page margin like the footer text above it */
  margin: clamp(32px, 5vw, 72px) 0 0 0.147em;
  color: var(--action);
  white-space: nowrap;
  user-select: none;
  position: relative;
}
/* The knights who joust along the foot of the letters, in front of all of them but the J.
   footer-joust.svg is drawn in thousandths of an em, baseline at 0 and the cap line at -700, and its
   view box starts at (-300, -620). Jost's line box puts the baseline 0.7075em down */
.footer-joust {
  position: absolute;
  z-index: 1;
  left: -0.3em;
  top: calc(0.7075em - 0.62em);
  width: 3.4em;
  height: 0.9em;
  max-width: none;
  pointer-events: none;
}
.footer-joust:not([src]) { display: none; }
/* On a phone the wordmark is only about 130px tall, which leaves the knights too small to make out.
   Scale the scene up around the baseline (620 of its 900 units down), so they still ride on it */
@media (max-width: 520px) {
  .footer-joust { transform: scale(1.6); transform-origin: 50% 68.9%; }
}
.footer-big span:first-child { position: relative; z-index: 2; }
.footer-big span {
  display: inline-block;
  transition: transform var(--dur-settle) var(--spring);
  /* With the line squeezed to 0.72em, each letter's text area (the font's ascender space, which has no
     ink) reaches far above the letter and covers the footer links, and browsers hit-test all of it.
     Clipping to the letter's own box, from just above the cap line to below the J's tail, keeps the
     letters exactly as they look and limits where they can be pointed at to the letters themselves.
     The tracking pulls each box in under its letter's right edge, the T's furthest at 0.05em, so the
     clip reaches 0.06em past it; on the left the letters start inside their boxes. The J is the
     exception: its tail curls 0.147em out to the left, and nothing of it reaches the right edge, so
     its clip stops there rather than reaching over the O (the J is on top, and would lift instead) */
  --reach: -0.3em;
  clip-path: inset(-0.02em -0.06em var(--reach) 0);
}
.footer-big span:first-child { clip-path: inset(-0.02em 0 var(--reach) -0.2em); }
.js .footer-big span { transform: translateY(0.5em); opacity: 0; transition: transform var(--dur-enter) var(--spring), opacity var(--dur-enter) var(--ease-out); transition-delay: calc(var(--i) * var(--stagger)); }
.js .footer-big.is-in span { transform: none; opacity: 1; }
/* A pointed-at letter lifts 0.08em. Its clipped area would lift with it and leave a pointer near the
   bottom (at the J's tail) outside, dropping the letter, which is then pointed at again, so it would
   flicker. While lifted, the area reaches 0.08em further down (and a little more for the spring's
   overshoot), so where you can point at it stays put */
@media (hover: hover) and (pointer: fine) {
  .footer-big span:hover { transform: translateY(-0.08em); --reach: -0.4em; }
  .js .footer-big.is-in span:hover { transform: translateY(-0.08em); transition-delay: 0s; }
}
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-s) var(--space-xl);
  margin-top: var(--space-xxl);
  font-size: var(--text-small);
  color: var(--text-muted);
}
@media (max-width: 860px) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--space-xxl); }
  .footer-grid > :first-child { grid-column: 1 / -1; }
}

/* MARK: - 404 */

.lost { min-height: 80vh; display: grid; place-items: center; text-align: center; padding: 160px 0 0; }
.lost .wrap { display: grid; gap: var(--space-xl); justify-items: center; }
/* A knight who's been knocked out: point at him and he topples, then gets back up */
.lost-knight { display: block; width: 140px; -webkit-tap-highlight-color: transparent; }
.lost-knight img { width: 100%; transform-origin: 50% 92%; transition: transform var(--dur-settle) var(--spring); }
.lost-knight.is-down img { transform: rotate(-82deg) translate(-6%, 4%); transition-timing-function: var(--ease-in); transition-duration: var(--dur-move); }
@media (hover: hover) and (pointer: fine) {
  .lost-knight:hover img { transform: rotate(-82deg) translate(-6%, 4%); transition-timing-function: var(--ease-in); transition-duration: var(--dur-move); }
}

/* MARK: - Moving between pages: the header stays where it is while the page underneath fades out and
   the next one rises in. Browsers without cross-document view transitions just navigate */

@view-transition { navigation: auto; }
.pill-bar { view-transition-name: site-nav; }
.status { view-transition-name: site-status; }
::view-transition-old(root) { animation: page-out calc(var(--dur-move) * 0.75) var(--ease-in) both; }
::view-transition-new(root) { animation: page-in var(--dur-enter) var(--ease-out) both; }
::view-transition-group(site-nav), ::view-transition-group(site-status) { animation-duration: var(--dur-move); animation-timing-function: var(--ease-in-out); }
@keyframes page-out { to { opacity: 0; } }
@keyframes page-in { from { opacity: 0; transform: translateY(8px); } }
/* Arriving that way, the page's own intro and reveals would rise a second time, so what's on screen
   just appears (the class is set by the inline script in each page's head) */
.is-arriving .intro { animation: none; }
.is-arriving .reveal, .is-arriving .reveal-items > * { opacity: 1; transform: none; transition: none; }

/* MARK: - Motion: content rises in as it scrolls into view */

.js .reveal, .js .reveal-items > * { opacity: 0; transform: translateY(12px); transition: opacity var(--dur-enter) var(--ease-out), transform var(--dur-enter) var(--ease-out); }
.js .reveal.is-in, .js .reveal-items.is-in > * { opacity: 1; transform: none; }
.js .reveal-items > * { transition-delay: calc(var(--i, 0) * var(--stagger)); }
/* The hero is there on the first frame and never waits for the script. Its words rise in over the
   scene one after another, starting straight away and done within 900ms */
.intro { animation: rise var(--dur-enter) var(--ease-out) both; animation-delay: calc(var(--n, 0) * var(--stagger)); }
@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
}

/* With Reduce Transparency on, the floating pills are solid */
@media (prefers-reduced-transparency: reduce) {
  .pill-bar, .status, .is-over-colour .pill-bar, .pill-bar.is-open { -webkit-backdrop-filter: none; backdrop-filter: none; background-color: var(--surface); }
  .hero-count { -webkit-backdrop-filter: none; backdrop-filter: none; background: #FFF8FA; }
}

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  html { scroll-behavior: auto; }
  .pill-bar, .site-nav a, .nav-toggle path { transition: none !important; }
  .intro { animation: none; }
  .roll .num, .hero-count-text, .hero-count-state, .hero-count-dots i, .hero-knight { transition: none; }
  .waitlist-field, .waitlist-done, .waitlist-heart-fill, .waitlist-spinner i { transition: none; animation: none; }
  .js .reveal, .js .reveal-items > * { opacity: 1; transform: none; transition: none; }
  .duel-heart.is-won, .knight.is-new .knight-shield { animation: none; }
  .knight-field[data-line]::after, .duel-reset, .table tbody td { transition: none; }
  .js .footer-big span { opacity: 1; transform: none; transition: none; }
  .nav-indicator, .segmented-thumb, .seat-grid i, .index-row .title { transition: none; }
  .metal::after, .dot { animation: none; }
  .ticker-track { animation: none; }
  .ticker-window { overflow-x: auto; }
  .button, .index-art, .toc-marker, .toc-toggle svg, .lost-knight img { transition: none; }
  .js .toc ol { transition: none; }
  .knight .knight-shield, .knight.is-playable .knight-shield, .duel-heart.is-won, .duel-busy { animation: none; transition: none; }
}
