/* ═══════════════════════════════════════════════════════════════════════════
   Rotaract Club of Hong Kong Island East · components.css
   The film's furniture and everything a page is built from. All of it comes from the
   logo (DIRECTION 4a): its two colours, its heavy-over-light lettering, the lockup as
   the layout of every title, and the parts of its wheel as every small shape:
     the tooth    bullets, ticks, the slate mark, the seam
     the window   small pictures, the pointer of the current page
     the ring     progress, radio buttons, focus
     the keyway   the loading mark, the tick of a checkbox
     the outline  the cog frame, medals

   Everything is in @layer components, so wheel.css and page CSS (unlayered) win.
   Components read the semantic tokens of base.css (--bg --fg --fg-muted --rule
   --focus --row --field …), never the raw palette, so a tone can re-point them.
   Nothing here animates a layout property: transforms, opacity, clip-path, masks.
   ═══════════════════════════════════════════════════════════════════════════ */

@layer components {

/* ─────────────────────────────────────────────────────── 1 Tones ──
   Dark throughout. A tone only shifts the ground one step and re-points what reads it. */
.section--night, .tone-night { --bg: var(--night); --row: var(--night-2); --row-hover: var(--black); --field: var(--black); }
.section--black, .tone-black { --bg: var(--black); --row: var(--night); --row-hover: var(--night-2); --field: var(--night); }
/* A large dim field of cranberry: bone text (7.8), bone focus ring, no cranberry-lit on it. */
.section--lit, .tone-lit, .panel--lit {
  --bg: var(--cranberry-deep); --fg: var(--bone); --fg-muted: var(--bone); --link: var(--bone); --focus: var(--bone); --accent: var(--white);
  --rule: rgb(242 236 230 / .28); --row: rgb(11 8 9 / .28); --field: var(--black);
  --btn-bg: var(--bone); --btn-fg: var(--black); --btn-bg-hover: var(--white); --btn-line: var(--bone);
}
.tone-night, .tone-black, .tone-lit { background: var(--bg); color: var(--fg); }

/* A pool of cranberry light: part of a scene, behind the wheel or at an edge. Decorative.
   Place it with --x / --y (the centre) and --size. */
.pool {
  position: absolute;
  inset-block-start: var(--y, 50%);
  inset-inline-start: var(--x, 50%);
  inline-size: var(--size, min(110vmin, 62rem));
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(closest-side, var(--light), var(--light-0));
  pointer-events: none;
}
.pool--dim { opacity: .5; }

/* ─────────────────────────────── 2 Icons, the wheel and its parts ── */
.sprite { position: absolute; inline-size: 0; block-size: 0; overflow: hidden; }
.sprite symbol[id^="i-"] :is(path, circle, rect, line, polyline, polygon, ellipse) { vector-effect: non-scaling-stroke; }
.icon { flex: none; inline-size: 1.5rem; block-size: 1.5rem; }
.icon--line { fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.icon--solid { fill: currentColor; }
.icon--up { rotate: -90deg; }
.icon--down { rotate: 90deg; }
.icon--back { rotate: 180deg; }
/* The wheel inline: one colour, the current one. Never stretched: it keeps its square. */
.wheel { display: block; aspect-ratio: 1; fill: currentColor; overflow: visible; }
.wheel__window { fill: transparent; }
.wheel__window.is-lit { fill: var(--cranberry); }

/* The tooth: one round-topped tooth of the rim, standing up. The bullet of every list, the tick of
   every scale, the mark that opens a slate line. Its size follows the text beside it. */
.tooth, .slate::before, .tooth-list > li::before, .field__error::before, .site-menu__link::before {
  flex: none;
  inline-size: calc(.78em * var(--tooth-ratio, 1.2));
  block-size: .78em;
  background: var(--accent);
  -webkit-mask: var(--tooth-mask) center / 100% 100% no-repeat;
  mask: var(--tooth-mask) center / 100% 100% no-repeat;
}
.tooth { display: inline-block; }
.tooth--white { background: var(--white); }

/* The window: the wedge between two spokes, upright (its point is down, towards the hub).
   A small picture or emblem sits in it (.frame--window); alone it is a pointer. */
.window-mark {
  display: inline-block;
  flex: none;
  inline-size: calc(.8em * var(--window-ratio, 1.1));
  block-size: .8em;
  background: var(--accent);
  -webkit-mask: var(--window-mask) center / 100% 100% no-repeat;
  mask: var(--window-mask) center / 100% 100% no-repeat;
}
.window-mark--up { rotate: 180deg; }

/* The keyway: the hub's "C" channel. Still, it is the tick of a checkbox; turning, it is the loading mark. */
.keyway, .loading-mark {
  display: inline-block;
  flex: none;
  inline-size: 1.15em;
  block-size: 1.15em;
  background: currentColor;
  -webkit-mask: var(--keyway-mask) center / contain no-repeat;
  mask: var(--keyway-mask) center / contain no-repeat;
}
@media (prefers-reduced-motion: no-preference) { .loading-mark { animation: rac-turn 1.2s linear infinite; } }
@keyframes rac-turn { to { rotate: 360deg; } }

/* The ring: the inner ring of the wheel, in its own thickness. A progress ring:
   <svg class="ring" viewBox="0 0 40 40" style="--p: .4"><circle class="ring__track" …/><circle class="ring__value" … pathLength="100"/></svg> */
.ring { display: block; inline-size: var(--ring-size, 3.5rem); aspect-ratio: 1; rotate: -90deg; overflow: visible; }
.ring circle { fill: none; stroke-width: calc(20px * var(--ring-share, .1226)); }
.ring__track { stroke: var(--line-strong); }
.ring__value { stroke: var(--accent); stroke-dasharray: calc(var(--p, 0) * 100) 100; transition: stroke-dasharray var(--dur-4) var(--ease-out); }

/* Six spokes make every six-way layout: six things round a centre in 60 degree steps, the first at the
   first window (30 degrees past twelve o'clock, as in the wheel). A plain folding grid under 56rem. */
.six { display: grid; gap: var(--gap, 1rem); grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 1fr)); }
.six > :nth-child(1) { --i: 0; } .six > :nth-child(2) { --i: 1; } .six > :nth-child(3) { --i: 2; }
.six > :nth-child(4) { --i: 3; } .six > :nth-child(5) { --i: 4; } .six > :nth-child(6) { --i: 5; }
@media (min-width: 56rem) {
  .six--round { position: relative; display: block; inline-size: min(100%, var(--six-size, 44rem)); aspect-ratio: 1; margin-inline: auto; }
  .six--round > * {
    --a: calc(var(--i) * 60deg + var(--six-turn, 30deg));
    position: absolute;
    inset-block-start: calc(50% - cos(var(--a)) * var(--six-r, 37%));
    inset-inline-start: calc(50% + sin(var(--a)) * var(--six-r, 37%));
    inline-size: var(--six-item, 26%);
    translate: -50% -50%;
  }
  .six--round > .six__hub { inset-block-start: 50%; inset-inline-start: 50%; inline-size: var(--six-hub, 30%); }
}

/* ─────────────────────────────────────────────── 3 Buttons and links ──
   Pills, 48px high at least. Primary = cranberry with a white label (5.1) and a small cog that turns.
   Secondary = a bone outline. The label says what happens. */
.btn {
  --pad: 1.5rem;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6em;
  min-block-size: var(--btn-h);
  padding: .55rem var(--pad);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  font-family: var(--font-text);
  font-size: 1.0625rem;
  font-weight: var(--fw-strong);
  line-height: var(--lh-ui);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-2) ease, border-color var(--dur-2) ease, color var(--dur-2) ease;
}
.btn--primary { background: var(--btn-bg); color: var(--btn-fg); }
.btn--primary::before {
  content: "";
  flex: none;
  inline-size: 1.15em;
  block-size: 1.15em;
  background: currentColor;
  -webkit-mask: var(--wheel-full-mask) center / contain no-repeat;
  mask: var(--wheel-full-mask) center / contain no-repeat;
  transition: rotate var(--dur-5) var(--ease-out);
}
.btn--primary:focus-visible::before { rotate: 120deg; }
.btn--primary:active, .btn--primary.is-pressed { background: var(--cranberry-deep); }
.btn--secondary { border-color: var(--btn-line); color: var(--fg); }
.btn--secondary:active, .btn--secondary.is-pressed { background: var(--bone-a10); }
.btn--sm { --btn-h: 2.75rem; --pad: 1.125rem; font-size: 1rem; }
.btn--lg { --btn-h: 3.5rem; --pad: 2rem; font-size: 1.125rem; }
.btn--block { display: flex; inline-size: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .6; cursor: default; }
.btn .loading-mark { display: none; }
@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover { background: var(--btn-bg-hover); }
  .btn--primary:hover::before { rotate: 120deg; }
  .btn--secondary:hover { border-color: var(--fg); background: var(--bone-a06); }
}

/* A text link that stands alone: bone, on a cranberry hairline. */
.link {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  min-inline-size: var(--target);
  min-block-size: var(--target);
  color: var(--fg);
  font-weight: var(--fw-strong);
  line-height: var(--lh-ui);
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: .35em;
  transition: text-decoration-thickness var(--dur-1) ease;
}
.link .icon { inline-size: 1.25rem; block-size: 1.25rem; }
@media (hover: hover) and (pointer: fine) { .link:hover { text-decoration-thickness: 2px; } }

/* Round 48px control and the quiet buttons of the bars. */
.round-btn {
  display: inline-grid;
  place-items: center;
  inline-size: 3rem;
  block-size: 3rem;
  border: 1px solid var(--btn-line);
  border-radius: 50%;
  color: var(--fg);
  transition: background-color var(--dur-2) ease, border-color var(--dur-2) ease;
}
.tool-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-inline-size: var(--target);
  min-block-size: var(--target);
  padding-inline: .5rem;
  border-radius: var(--r-full);
  color: var(--ash);
  font-size: 1rem;
  font-weight: var(--fw-strong);
  line-height: var(--lh-ui);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-2) ease;
}
.tool-btn:active, .tool-btn.is-pressed, .round-btn:active, .round-btn.is-pressed { color: var(--bone); background: var(--bone-a10); }
@media (hover: hover) and (pointer: fine) {
  .tool-btn:hover { color: var(--bone); }
  .round-btn:hover { border-color: var(--fg); background: var(--bone-a06); }
}
/* A pause / play pair inside one button. */
[data-motion-toggle] .icon--play { display: none; }
[data-motion-toggle][aria-pressed="true"] .icon--play { display: block; }
[data-motion-toggle][aria-pressed="true"] .icon--pause { display: none; }

/* ───────────────────────────────── 4 The letterbox, the grain, the bars ──
   Two fixed bars frame the picture. The header lies on the top one, the HUD on the bottom one.
   Each bar is a tall panel of the page's own black, moved by transform alone; --lb-top / --lb-bot say
   how much of it shows (core.js sets them on .letterbox; without scripts they are the thin bands). */
.letterbox { position: fixed; inset: 0; z-index: var(--z-bars); pointer-events: none; }
.letterbox__bar {
  position: absolute;
  inset-inline: 0;
  block-size: 52vh;
  background: var(--black);
  pointer-events: auto;
  transition: transform var(--dur-5) var(--ease-film);
}
.letterbox__bar--top {
  inset-block-start: 0;
  border-block-end: 1px solid var(--line);
  transform: translate3d(0, calc(var(--lb-top, var(--bar-top)) - 100%), 0);
}
.letterbox__bar--bottom {
  inset-block-end: 0;
  transform: translate3d(0, calc(100% - var(--lb-bot, var(--bar-bot))), 0);
}
.letterbox.is-live .letterbox__bar { transition: none; }
@media (prefers-reduced-motion: reduce) { .letterbox__bar { transition: none; } }
.letterbox__probe { position: absolute; inset-block-start: 0; inset-inline-start: 0; inline-size: 1px; visibility: hidden; pointer-events: none; }
.letterbox__probe--film { block-size: var(--film-bar); }
.letterbox__probe--closed { block-size: var(--closed-bar); }

/* The playhead: the edge of the bottom bar is its line, a small cog rolls along it, and each tick is a tooth. */
.playhead {
  position: absolute;
  inset-inline: 0;
  inset-block-start: -1rem;
  block-size: 1.5rem;
  cursor: pointer;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  outline-offset: -3px;
}
.playhead__line { position: absolute; inset-inline: 0; inset-block-start: 1rem; block-size: 1px; background: var(--line); }
.playhead__done { position: absolute; inset: 0; background: var(--cranberry); transform-origin: 0 50%; transform: scaleX(0); }
.playhead__ticks { position: absolute; inset-inline: 0; inset-block-start: 1rem; block-size: 0; }
.playhead__ticks > span {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: calc(var(--at) * 100%);
  inline-size: calc(.4rem * var(--tooth-ratio, 1.2));
  block-size: .4rem;
  translate: -50% 0;
  rotate: 180deg;
  background: var(--ash);
  -webkit-mask: var(--tooth-mask) center / 100% 100% no-repeat;
  mask: var(--tooth-mask) center / 100% 100% no-repeat;
}
.playhead__cog {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: calc(1rem - var(--cog, 1.125rem));
  inline-size: var(--cog, 1.125rem);
  block-size: var(--cog, 1.125rem);
  color: var(--cranberry);
  pointer-events: none;
}
.playhead__cog .wheel { inline-size: 100%; block-size: 100%; }
.playhead:focus-visible .playhead__cog { color: var(--white); }

/* Grain and vignette: one fixed overlay over the picture, under the bars. Plain opacity only.
   The grain is a small tile of noise (the art producer's img/art/grain-1.png when it exists: the build
   points --grain at it; otherwise the turbulence below) moved in steps, eight to the second. It holds
   still under reduced motion, when motion is paused, and when a scene asks (RAC.grain.still). */
.film { position: fixed; inset: 0; z-index: var(--z-film); overflow: hidden; pointer-events: none; contain: strict; }
.film__vignette { position: absolute; inset: 0; background: radial-gradient(ellipse 125% 95% at 50% 50%, rgb(11 8 9 / 0) 52%, rgb(11 8 9 / .6) 100%); }
.film__grain {
  position: absolute;
  inset: -4rem;
  background-image: var(--grain, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  1.7 0 0 0 -.62'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E"));
  background-size: var(--grain-size, 200px) var(--grain-size, 200px);
  opacity: var(--grain-opacity, .16);
}
@media (prefers-reduced-motion: no-preference) {
  html.js .film__grain { animation: rac-grain 1s steps(1) infinite; }
}
html.is-grain-still .film__grain, html.is-motion-paused .film__grain { animation-play-state: paused; }
@keyframes rac-grain {
  0% { transform: translate3d(0, 0, 0); }
  12.5% { transform: translate3d(-23px, 17px, 0); }
  25% { transform: translate3d(31px, -9px, 0); }
  37.5% { transform: translate3d(-11px, -27px, 0); }
  50% { transform: translate3d(19px, 29px, 0); }
  62.5% { transform: translate3d(-33px, 5px, 0); }
  75% { transform: translate3d(7px, -19px, 0); }
  87.5% { transform: translate3d(-17px, 23px, 0); }
}

/* The page-change wipe grows from the wheel of the header logo (base.css). Its box is 60vmax across,
   centred on that wheel; nothing in it is ever seen outside a page change. */
.wipe-anchor {
  position: fixed;
  inset-block-start: calc(var(--wipe-y) - 30vmax);
  inset-inline-start: calc(var(--wipe-x) - 30vmax);
  inline-size: 60vmax;
  block-size: 60vmax;
  pointer-events: none;
  view-transition-name: rac-wipe;
}

/* The header, on the top bar. */
.site-header { position: fixed; inset-block-start: 0; inset-inline: 0; z-index: var(--z-header); block-size: var(--header-h); pointer-events: none; }
.site-header__bar {
  display: flex;
  align-items: center;
  column-gap: clamp(.5rem, 1.6vw, 1.75rem);
  block-size: 100%;
  padding-inline: var(--gutter);
  pointer-events: auto;
}
.brand { display: inline-flex; flex: none; align-items: center; min-block-size: var(--target); }
.brand__logo { inline-size: auto; block-size: var(--logo-h); max-inline-size: none; }
.brand__standin { display: block; inline-size: var(--logo-h); block-size: var(--logo-h); color: var(--white); }
.brand__standin .wheel { inline-size: 100%; block-size: 100%; }
.site-nav { margin-inline-start: auto; }
.site-nav__list { display: flex; align-items: center; gap: clamp(0rem, .9vw, 1rem); }
.site-nav__link {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--target);
  padding-inline: .7rem;
  color: var(--ash);
  font-size: 1rem;
  font-weight: var(--fw-strong);
  line-height: var(--lh-ui);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-2) ease;
}
.site-nav__link > span { position: relative; padding-block: .6rem; }
/* The current page, and the link under the pointer, is pointed at by one window of the wheel. */
.site-nav__link > span::after {
  content: "";
  position: absolute;
  inset-inline-start: 50%;
  inset-block-end: -.1rem;
  inline-size: calc(.55rem * var(--window-ratio, 1.1));
  block-size: .55rem;
  margin-inline-start: calc(.55rem * var(--window-ratio, 1.1) / -2);
  background: var(--cranberry);
  -webkit-mask: var(--window-mask) center / 100% 100% no-repeat;
  mask: var(--window-mask) center / 100% 100% no-repeat;
  rotate: 180deg;
  opacity: 0;
  transform: translate3d(0, -.35rem, 0);
  transition: opacity var(--dur-2) ease, transform var(--dur-3) var(--ease-out);
}
.site-nav__link[aria-current="page"] { color: var(--bone); }
.site-nav__link[aria-current="page"] > span::after { opacity: 1; transform: none; }
@media (hover: hover) and (pointer: fine) {
  .site-nav__link:hover { color: var(--bone); }
  .site-nav__link:hover > span::after { opacity: 1; transform: none; }
}
.site-tools { display: flex; flex: none; align-items: center; gap: .25rem .5rem; }
.site-header__cta { margin-inline-start: .25rem; white-space: nowrap; }
.lang-btn .icon, .menu-btn .icon { inline-size: 1.375rem; block-size: 1.375rem; }
.menu-btn { display: none; }
/* What fits is measured (header.html): data-level 0 … 4. */
.site-header:is([data-level="1"], [data-level="2"], [data-level="3"], [data-level="4"]) .lang-btn__name { display: none; }
.site-header:is([data-level="2"], [data-level="3"], [data-level="4"]) .site-nav { display: none; }
.site-header:is([data-level="2"], [data-level="3"], [data-level="4"]) .menu-btn { display: inline-flex; }
.site-header:is([data-level="2"], [data-level="3"], [data-level="4"]) .site-tools { margin-inline-start: auto; }
.site-header:is([data-level="3"], [data-level="4"]) .menu-btn__label { display: none; }
.site-header[data-level="4"] .site-header__cta { display: none; }
/* Without scripts nothing is measured: a plain breakpoint, and the two buttons lead to the footer's lists. */
@media (max-width: 61.99rem) {
  html:not(.js) .site-nav, html:not(.js) .lang-btn__name { display: none; }
  html:not(.js) .menu-btn { display: inline-flex; }
  html:not(.js) .site-tools { margin-inline-start: auto; }
}
@media (max-width: 27.99rem) {
  html:not(.js) .menu-btn__label { display: none; }
}

/* The HUD, on the bottom bar: where you are, the sound switch, "Skip to joining". Slate type. */
.hud {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  block-size: var(--bar-bot);
  padding-inline: var(--gutter);
  padding-block-end: var(--safe-b);
  color: var(--ash);
  font-size: var(--fs-slate);   /* lint-ok: the HUD is slate furniture */
  font-weight: var(--fw-slate);
  line-height: var(--lh-ui);
  letter-spacing: var(--tracking-slate);
  text-transform: var(--case-slate);
  font-variant-numeric: tabular-nums lining-nums;
  pointer-events: none;
}
.hud > * { pointer-events: auto; }
.hud__where { display: flex; align-items: center; gap: .7em; min-inline-size: 0; max-inline-size: none; white-space: nowrap; }
.hud__tooth { flex: none; inline-size: calc(.78em * var(--tooth-ratio, 1.2)); block-size: .78em; background: var(--cranberry); -webkit-mask: var(--tooth-mask) center / 100% 100% no-repeat; mask: var(--tooth-mask) center / 100% 100% no-repeat; }
.hud__part { flex: none; color: var(--bone); font-weight: var(--fw-text); }
.hud__title { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; }
.hud__part:not([hidden]) + .hud__title { padding-inline-start: .7em; border-inline-start: 1px solid var(--line-strong); }
.hud__tools { display: flex; flex: none; align-items: center; gap: .25rem clamp(.5rem, 2vw, 1.5rem); }
.hud__btn {
  display: inline-flex;
  align-items: center;
  gap: .5em;
  min-block-size: var(--target);
  padding-inline: .25rem;
  color: var(--bone);
  font: inherit;
  font-weight: var(--fw-text);
  letter-spacing: inherit;
  text-transform: inherit;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.hud__skip { text-decoration: underline; text-decoration-color: var(--cranberry); text-decoration-thickness: 1px; text-underline-offset: .4em; }
/* Play / Pause: the film scrolls by itself (RAC.film). The words change with the state; on a phone the icon stands alone. */
.hud__play { color: var(--white); font-weight: var(--fw-strong); }
.hud__play .icon { inline-size: 1.25rem; block-size: 1.25rem; color: var(--cranberry-lit); }
.hud__play .hud__play-stop { display: none; }
.hud__play[data-film-state="playing"] .hud__play-stop { display: block; }
.hud__play[data-film-state="playing"] .hud__play-go { display: none; }
.hud__sound .icon { inline-size: 1.25rem; block-size: 1.25rem; }
.hud__sound .hud__sound-on { display: none; }
.hud__sound[aria-pressed="true"] .hud__sound-on { display: block; color: var(--cranberry-lit); }
.hud__sound[aria-pressed="true"] .hud__sound-off { display: none; }
.hud__sound-state { color: var(--ash); font-weight: var(--fw-slate); }
@media (hover: hover) and (pointer: fine) { .hud__skip:hover { text-decoration-thickness: 2px; } }
@media (max-width: 40rem) {
  .hud { gap: .5rem; }
  .hud__sound-label { display: none; }
  .hud__where { gap: .5em; }
  .hud__play { min-inline-size: var(--target); justify-content: center; }
  .hud__play-label { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* ───────────────────────────────────── 5 Overlays: the menu, the languages ──
   Native <dialog>s that open like an iris from the button that called them (--ox / --oy / --or). */
.overlay {
  position: fixed;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  max-inline-size: none;
  max-block-size: none;
  margin: 0;
  overflow: hidden;
  background: var(--black);
  color: var(--bone);
  clip-path: circle(0px at var(--ox, 92%) var(--oy, 2rem));
  transition: clip-path var(--dur-4) var(--ease-film);
}
.overlay:not(.is-open) { transition-duration: 380ms; }   /* it closes faster than it opens */
.overlay[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
.overlay.is-open { clip-path: circle(var(--or, 150vmax) at var(--ox, 92%) var(--oy, 2rem)); }
.overlay::backdrop { background: transparent; }
.overlay:focus { outline: none; }
.overlay__wheel {
  position: absolute;
  inset-block-end: -28vmin;
  inset-inline-end: -22vmin;
  inline-size: min(110vmin, 58rem);
  aspect-ratio: 1;
  color: var(--night);
  pointer-events: none;
}
.overlay__wheel .wheel { inline-size: 100%; block-size: 100%; }
@media (prefers-reduced-motion: no-preference) {
  .overlay.is-open .overlay__wheel .wheel { animation: rac-turn 120s linear infinite; }
}
.overlay__bar { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-block-size: var(--header-h); padding-inline: var(--gutter); border-block-end: 1px solid var(--line); }
.overlay__body { position: relative; overflow-y: auto; overscroll-behavior: contain; padding: clamp(1.5rem, 1rem + 3vw, 3.5rem) var(--gutter) calc(2rem + var(--safe-b)); }
.overlay [data-cascade] > * { opacity: 0; transform: translate3d(0, 1.25rem, 0); transition: opacity var(--dur-3) ease, transform var(--dur-4) var(--ease-out); transition-delay: calc(var(--i, 0) * 55ms + 160ms); }
.overlay.is-open [data-cascade] > * { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .overlay { clip-path: none; transition: none; }
  .overlay [data-cascade] > * { opacity: 1; transform: none; transition: none; }
}

.site-menu__body { display: grid; align-content: start; gap: clamp(2rem, 1.5rem + 3vw, 3.5rem); }
.site-menu__list { display: grid; gap: .25rem; }
.site-menu__link {
  display: inline-flex;
  align-items: center;
  gap: .35em;
  min-block-size: 3.25rem;
  color: var(--bone);
  font-family: var(--font-display);
  font-size: calc(clamp(2rem, 1.5rem + 2.6vw, 3.5rem) * var(--display-scale));
  font-weight: var(--fw-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  text-decoration: none;
}
.site-menu__link::before { content: ""; inline-size: calc(.5em * var(--tooth-ratio, 1.2)); block-size: .5em; background: var(--cranberry); opacity: 0; rotate: 90deg; transition: opacity var(--dur-2) ease; }
.site-menu__link[aria-current="page"] { color: var(--cranberry-lit); }
.site-menu__link[aria-current="page"]::before, .site-menu__link.is-pressed::before { opacity: 1; }
@media (hover: hover) and (pointer: fine) { .site-menu__link:hover::before { opacity: 1; } }
.site-menu__tools { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.25rem; }
.site-menu__tools .lang-btn { color: var(--bone); }
.site-menu__note { flex-basis: 100%; }

.lang-panel__title { font-family: var(--font-display); font-size: var(--fs-sub); font-weight: var(--fw-title); line-height: var(--lh-sub); }
.lang-panel__body { display: grid; align-content: start; gap: 2rem; }
.lang-list { display: grid; max-inline-size: 40rem; border-block-end: 1px solid var(--line); }
.lang-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 1rem;
  min-block-size: 4.5rem;
  padding-block: .75rem;
  border-block-start: 1px solid var(--line);
  color: var(--bone);
  text-decoration: none;
}
.lang-row__native { font-family: var(--font-display); font-size: calc(clamp(1.5rem, 1.25rem + 1.2vw, 2.125rem) * var(--display-scale)); font-weight: var(--fw-title); line-height: var(--lh-sub); }
.lang-row__english { color: var(--ash); font-size: 1rem; font-weight: var(--fw-light); }
.lang-row__current { display: grid; place-items: center; inline-size: 2rem; block-size: 2rem; border-radius: 50%; background: var(--cranberry); color: var(--white); }
.lang-row__current .keyway { inline-size: 1.125rem; block-size: 1.125rem; }
.lang-row:active, .lang-row.is-pressed { background: var(--night); }
@media (hover: hover) and (pointer: fine) { .lang-row:hover .lang-row__native { color: var(--cranberry-lit); } }
.lang-panel__note { font-size: 1rem; }

/* ─────────────────────────────────────────────── 6 The suggestion bar ── */
.suggest {
  position: fixed;
  inset-block-end: calc(var(--bar-bot) + .75rem);
  inset-inline: .75rem;
  z-index: var(--z-suggest);
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .5rem .5rem .5rem .875rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-panel);
  background: var(--night-2);
  color: var(--bone);
  opacity: 0;
  transform: translate3d(0, 1rem, 0);
  transition: opacity var(--dur-3) ease, transform var(--dur-4) var(--ease-out);
}
.suggest.is-in { opacity: 1; transform: none; }
.suggest__icon { display: none; color: var(--cranberry-lit); }
.suggest__text { flex: 1 1 auto; min-inline-size: 0; max-inline-size: none; font-size: 1rem; line-height: var(--lh-ui); }
.suggest__text:empty { display: none; }
.suggest__actions { display: flex; flex: none; align-items: center; gap: .25rem; margin-inline-start: auto; }
.suggest__no-label { display: none; }
@media (max-width: 47.99rem) {
  .suggest__text { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }   /* read out, not shown: the button says it */
}
@media (min-width: 48rem) {
  .suggest { inset-inline: auto var(--gutter); max-inline-size: min(44rem, 100% - 2 * var(--gutter)); padding: .625rem .625rem .625rem 1.25rem; border-radius: var(--r-full); }
  .suggest__icon { display: block; }
  .suggest__no-label { display: inline; }
  .suggest__no .icon { display: none; }
}
@media (prefers-reduced-motion: reduce) { .suggest { transition: none; transform: none; } }

/* ─────────────────────────────────────────────────── 7 The preloader ──
   Only while <html> has rac-intro (first page view of a session, never under reduced motion).
   CSS draws the wheel tooth by tooth and can finish alone; core.js adds the hand-over.
   The first tooth is the one tooth of light: white, then cranberry like the rest. */
.preloader { display: none; }
html.rac-intro .preloader {
  position: fixed;
  inset: 0;
  z-index: var(--z-preloader);
  display: grid;
  place-items: center;
  animation: rac-pre-gone .01s 1.85s forwards;
}
/* The black ground is a layer of its own, under the wheel. It can finish alone: 1.4 s after first paint the
   ground and the wheel fade (opacity only, so the browser can do it even while a script is busy), and the
   page's title, painted long before underneath, is on show. core.js normally gets there first (is-handoff):
   then the ground lifts in 0.3 s as the wheel flies to its place. */
html.rac-intro .preloader::before { content: ""; position: absolute; inset: 0; z-index: -1; background: var(--black); will-change: opacity; animation: rac-pre-back .4s 1.4s ease forwards; }
html.rac-intro .preloader__wheel { animation: rac-pre-back .4s 1.4s ease forwards; }
html.rac-intro .preloader.is-handoff { animation: none; pointer-events: none; }
html.rac-intro .preloader.is-handoff::before { animation: rac-pre-lift .3s ease-out forwards; }   /* its own name: a new animation, from the start */
html.rac-intro .preloader.is-handoff .preloader__wheel { animation: none; }
.preloader__wheel { inline-size: min(36vmin, 15rem); aspect-ratio: 1; color: var(--cranberry); }
.preloader__svg { inline-size: 100%; block-size: 100%; animation: rac-pre-turn 1.9s linear both; }
.preloader .wheel__tooth { opacity: 0; animation: rac-tooth .22s calc(.1s + var(--i) / var(--wheel-teeth) * .72s) ease-out both; }
.preloader .wheel__tooth:first-child { animation-name: rac-tooth-first; animation-duration: 1.1s; animation-delay: .06s; }
.preloader .wheel__body { opacity: 0; animation: rac-tooth .38s .84s ease-out both; }
@keyframes rac-tooth { from { opacity: 0; } to { opacity: 1; } }
@keyframes rac-tooth-first { 0% { opacity: 0; fill: var(--white); } 16% { opacity: 1; fill: var(--white); } 78% { fill: var(--white); } 100% { opacity: 1; fill: var(--cranberry); } }
@keyframes rac-pre-turn { from { rotate: 0deg; } to { rotate: 30deg; } }
@keyframes rac-pre-back { to { opacity: 0; } }
@keyframes rac-pre-lift { from { opacity: 1; } to { opacity: 0; } }
@keyframes rac-pre-gone { to { visibility: hidden; } }
/* While the intro runs, the place the wheel will land holds its breath. */
html.rac-intro [data-intro-target] { visibility: hidden; }

/* ───────────────────────────────────────── 8 The footer and the seam ── */
.site-footer { position: relative; padding-block: var(--section-pad) calc(var(--bar-bot) + var(--dock-h) + 2rem); background: var(--bg); color: var(--fg); }
.site-footer__inner { display: grid; gap: clamp(2.5rem, 2rem + 3vw, 4.5rem); }
.site-footer__lead { display: grid; gap: 2.5rem; align-items: center; }
.site-footer__about { display: grid; gap: 1rem; justify-items: start; }
.site-footer .brand__logo { block-size: clamp(3rem, 2.4rem + 2.4vw, 4.25rem); }
.site-footer .brand__standin { inline-size: 4rem; block-size: 4rem; }
.site-footer__desc { font-family: var(--font-display); font-size: var(--fs-sub); font-weight: var(--fw-light); line-height: 1.35; letter-spacing: var(--tracking-light); max-inline-size: 30em; text-wrap: balance; }
.site-footer__family { display: grid; gap: .25rem; color: var(--fg-muted); }
/* The slot for the footer wheel (the signature builder's piece). Its tracks are sized here and not by the
   piece: the piece keeps a whole list in one cell, and an auto track would grow to its longest line. */
.site-footer__wheel { justify-self: center; inline-size: min(100%, 28rem); min-inline-size: 0; }
.site-footer__grid { display: grid; gap: 2rem clamp(2rem, 6vw, 6rem); grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), max-content)); padding-block-start: clamp(2rem, 1.6rem + 2vw, 3rem); border-block-start: 1px solid var(--rule); }
.site-footer__col { display: grid; gap: .75rem; align-content: start; }
.site-footer__col:focus { outline: none; }
.site-footer__links { display: grid; gap: 0; }
.site-footer__links a { display: inline-flex; align-items: center; gap: .6rem; min-inline-size: var(--target); min-block-size: var(--target); color: var(--bone); font-weight: var(--fw-strong); text-decoration: none; }
.site-footer__links a[aria-current] { color: var(--cranberry-lit); }
.site-footer__links .icon { inline-size: 1.25rem; block-size: 1.25rem; }
@media (hover: hover) and (pointer: fine) { .site-footer__links a:hover { text-decoration: underline; text-decoration-color: var(--cranberry); text-underline-offset: .35em; } }
.site-footer__legal { display: grid; gap: .5rem; color: var(--fg-muted); font-size: 1rem; }
.site-footer__legal p { max-inline-size: 60em; }
.site-footer__base { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 2rem; padding-block-start: 1.25rem; border-block-start: 1px solid var(--rule); color: var(--fg-muted); font-size: 1rem; }
.site-footer__tools { display: flex; align-items: center; gap: .5rem 1.25rem; }
.backtotop .icon { inline-size: 1.125rem; block-size: 1.125rem; }
@media (min-width: 56rem) {
  .site-footer__lead { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); }
  .site-footer__lead > :only-child { grid-column: 1 / -1; }
  .site-footer__wheel { justify-self: end; }
}

/* The toothed seam: the wheel's rim, straightened. Put <div class="seam" aria-hidden="true"></div> first in
   a section: a row of teeth in that section's own ground stands up into the section above. With data-seam
   the row travels as the page scrolls (core.js moves --seam-x). */
.seam { position: absolute; inset-inline: 0; inset-block-end: calc(100% - 1px); block-size: var(--seam-h); overflow: hidden; pointer-events: none; }
.seam::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline: -12rem;
  background: var(--seam-colour, var(--bg));
  -webkit-mask: var(--teeth-mask) 0 0 / calc(var(--seam-h) * var(--teeth-ratio)) 100% repeat-x;
  mask: var(--teeth-mask) 0 0 / calc(var(--seam-h) * var(--teeth-ratio)) 100% repeat-x;
  transform: translate3d(var(--seam-x, 0px), 0, 0);
}
.seam--lit { --seam-colour: var(--cranberry); }
.seam--down { inset-block: calc(100% - 1px) auto; rotate: 180deg; }   /* teeth hang from the foot of the section instead */

/* ───────────────────── 9 The lockup, the slate line, title cards, page heads, scenes ── */

/* The slate line: the small light line above a title (part number, year). Title cards and dated
   entries only. It opens with one tooth; several items are parted by a hairline. Uppercase in English. */
.slate {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4em .8em;
  max-inline-size: none;
  color: var(--fg-muted);
  font-family: var(--font-text);
  font-size: var(--fs-slate);   /* lint-ok: the slate line */
  font-weight: var(--fw-slate);
  line-height: var(--lh-ui);
  letter-spacing: var(--tracking-slate);
  text-transform: var(--case-slate);
  font-variant-numeric: tabular-nums lining-nums;
}
.slate::before { content: ""; }
/* Only between the slate's own items. The build writes spans of its own straight into a label (.nb round a name,
   .w round a Chinese word): those are the words of one item, never items. */
.slate > span:not(.nb, .w) + span:not(.nb, .w) { padding-inline-start: .8em; border-inline-start: 1px solid var(--line-strong); }
.slate--plain::before { display: none; }
.slate--white::before { background: var(--white); }
.slate--bone { color: var(--bone); }

/* The lockup (DIRECTION 4a): the layout of every title is the layout of the logo. A wheel at the start
   side; beside it the title, heavy, and a second line, light; both aligned to the start edge; in the
   logo's own proportions and weights (base.css: --lockup-wheel, --lockup-gap, --lockup-sub, --lockup-rise,
   all in ems of the title's size; the art producer measured them, src/img/logo/logo.json → lockup). The lockup partial writes this markup. For part n of the six, n of the
   wheel's six windows are lit. */
.lockup {
  --lockup-fs: var(--fs-section);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--lockup-gap);
  align-items: start;
  justify-items: start;
  inline-size: fit-content;
  max-inline-size: 100%;
  font-size: var(--lockup-fs);
  text-align: start;
}
.lockup--title { --lockup-fs: var(--fs-title); }
.lockup--hero { --lockup-fs: var(--fs-hero); }
.lockup--section { --lockup-fs: var(--fs-section); }
.lockup--sub { --lockup-fs: var(--fs-sub); }
.lockup > .slate { grid-column: 1 / -1; margin-block-end: clamp(1rem, .8rem + 1vw, 1.75rem); }
.lockup__wheel { inline-size: var(--lockup-wheel); block-size: var(--lockup-wheel); color: var(--lockup-colour, var(--heading)); }
.lockup__wheel .wheel { inline-size: 100%; block-size: 100%; }
.lockup__wheel .wheel__window { transition: fill var(--dur-5) ease; }
.lockup__words { display: grid; justify-items: start; min-inline-size: 0; padding-block-start: var(--lockup-rise); }
.lockup__title {
  margin: 0;
  max-inline-size: 20ch;
  color: var(--heading);
  font-family: var(--font-display);
  font-size: 1em;
  font-weight: var(--fw-display);
  line-height: var(--lh-display);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
  overflow-wrap: anywhere;
}
.lockup--sub .lockup__title { font-weight: var(--fw-title); line-height: var(--lh-sub); letter-spacing: var(--tracking-sub); }
.lockup__sub {
  /* From the heavy baseline to the light one, as in the logo (--lockup-step-em of the title): take away what the
     two line boxes give by themselves (the foot of the title's last line, the head of this one) and the rest is
     the margin. The light line's text box also starts a hair further in, as the logo's does. All in this line's ems. */
  margin-block-start: calc((var(--lockup-step-em, .7901) - ((var(--lh-display) - var(--font-box)) / 2 + var(--font-descent)) - ((1.25 - var(--font-box)) / 2 + var(--font-ascent)) * var(--lockup-sub-em, .5799)) / var(--lockup-sub-em, .5799) * 1em);
  margin-inline-start: calc(var(--lockup-inset-em, .0751) * 1em);
  max-inline-size: 34ch;
  color: var(--heading);
  font-family: var(--font-display);
  font-size: var(--lockup-sub);
  font-weight: var(--fw-light);
  line-height: 1.25;
  letter-spacing: var(--tracking-light);
  text-wrap: balance;
}
/* A second line may never be smaller than running text allows. */
.lockup--section .lockup__sub, .lockup--sub .lockup__sub { font-size: max(var(--lockup-sub), 1.0625rem); }
.lockup__rule { grid-column: 1 / -1; display: block; inline-size: min(100%, 14rem); block-size: 1px; margin-block-start: clamp(1.25rem, 1rem + 1.2vw, 2.25rem); background: var(--line-strong); transform-origin: 0 50%; }
.lockup--cranberry { --lockup-colour: var(--cranberry); }
/* A small heading inside a card: one lit window in place of the wheel. */
.lockup--mark { column-gap: .5em; }
.lockup--mark .lockup__wheel { inline-size: calc(var(--cap) * 1.15em * var(--window-ratio, 1.1)); block-size: calc(var(--cap) * 1.15em); margin-block-start: calc(((var(--lh-sub) - var(--font-box)) / 2 + var(--font-ascent) - var(--cap) * 1.075) * 1em); background: var(--cranberry); -webkit-mask: var(--window-mask) center / 100% 100% no-repeat; mask: var(--window-mask) center / 100% 100% no-repeat; }
.lockup--mark .lockup__words { padding-block-start: 0; }
/* mark='tooth': one tooth in place of the window. --lockup-mark colours either mark. */
.lockup--mark .lockup__wheel { background: var(--lockup-mark, var(--cranberry)); }
.lockup--mark-tooth { column-gap: .6em; }
.lockup--mark-tooth .lockup__wheel { inline-size: calc(var(--cap) * 1.15em * var(--tooth-ratio, 1.2)); -webkit-mask-image: var(--tooth-mask); mask-image: var(--tooth-mask); }
.lockup--mark.lockup--white { --lockup-mark: var(--white); }

/* A title card: black, a lockup in the middle of the stage (itself aligned to its start edge, as the logo is). */
.title-card { display: grid; justify-items: center; padding-inline: var(--gutter); }
.title-card--start { justify-items: start; padding-inline: 0; }
.title-card > * + * { margin-block-start: var(--space-m); }
.title-card__line { max-inline-size: 30em; color: var(--fg-muted); font-size: var(--fs-lead); font-weight: var(--fw-light); text-wrap: balance; }

/* The head of a practical page: a lockup, then room for a lead and actions. */
.page-head { position: relative; padding-block: calc(var(--clear-top, var(--bar-top)) + clamp(3rem, 2rem + 6vw, 7.5rem)) clamp(2.5rem, 2rem + 3vw, 5rem); background: var(--bg); overflow: clip; }
.page-head__inner { position: relative; display: grid; gap: var(--space-m); justify-items: start; }
.page-head__inner > .lead { max-inline-size: 34em; color: var(--fg-muted); }

/* A film scene. With scripts and motion (html.film-on) its stage fills the screen and sits inside the
   film bars; otherwise it is plain stacked content. core.js pins and scrubs it (data-scene). */
.scene { position: relative; background: var(--black); overflow: clip; }
.scene__stage { position: relative; display: grid; align-content: center; gap: var(--space-l); padding-block: calc(var(--section-pad) * .7 + var(--clear-top, 0px)) calc(var(--section-pad) * .7); }
html.film-on .scene__stage { min-block-size: 100svh; padding-block: calc(var(--film-bar) + 1.25rem); }
.scene__layer { position: absolute; inset: 0; pointer-events: none; }

/* ───────────────────────── 10 Frames, the placeholder, subtitles, captions ──
   Photographs sit in a 2.39:1 film frame with a hairline, or in the cog frame (the wheel's outer outline);
   small pictures and emblems in one window of the wheel. They open like an iris (data-reveal="iris"),
   never fade up. Each carries its dated caption. */
.frame { position: relative; display: block; overflow: hidden; aspect-ratio: var(--ar, 3 / 2); background: var(--ph, var(--night)); isolation: isolate; }
.frame > :is(picture, img, .ph) { position: absolute; inset: 0; display: block; inline-size: 100%; block-size: 100%; }
.frame picture > img { display: block; inline-size: 100%; block-size: 100%; }
.frame img { object-fit: cover; object-position: var(--focal-x, 50%) var(--focal-y, 50%); }
.frame--film { --ar: 2.39 / 1; }
.frame--film::after, .frame--line::after { content: ""; position: absolute; inset: 0; z-index: 2; border: 1px solid var(--line); pointer-events: none; }
/* The mask sits a hair inside its box: stretched edge to edge, WebKit smears the tips of the teeth into a
   hairline along the box's edge whenever the box lands on a fraction of a pixel. */
.frame--cog { --ar: 1 / 1; -webkit-mask: var(--wheel-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat; mask: var(--wheel-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat; }
.frame--window { aspect-ratio: var(--window-ratio, 1.1); -webkit-mask: var(--window-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat; mask: var(--window-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat; }
.frame--square { --ar: 1 / 1; }
.frame--portrait { --ar: 4 / 5; }
.frame--tall { --ar: 2 / 3; }
.frame--landscape { --ar: 4 / 3; }
.frame--wide { --ar: 16 / 9; }
.frame--past :is(img, .ph) { opacity: .58; }   /* the one thing CSS adds to a graded photograph: the past is dim */

/* The placeholder frame: what picture() returns while a photograph does not exist yet. Never a broken image. */
.ph { display: grid; place-content: center; justify-items: center; gap: .6rem; inline-size: 100%; block-size: 100%; min-block-size: 5rem; padding: 8%; overflow: hidden; background: radial-gradient(circle at 50% 46%, rgb(142 12 69 / .5), var(--night-2) 72%); color: var(--ash); }
.ph__wheel { inline-size: clamp(2.5rem, 34%, 8rem); aspect-ratio: 1; fill: rgb(242 236 230 / .16); }
.ph__slug { max-inline-size: 100%; overflow: hidden; font-size: var(--fs-slate); font-weight: var(--fw-slate); line-height: var(--lh-ui); text-align: center; text-overflow: ellipsis; white-space: nowrap; }   /* lint-ok: builder's label on a placeholder */
:not(.frame) > .ph { aspect-ratio: 3 / 2; }

.figure { display: grid; gap: .75rem; margin: 0; }
.figure > figcaption, .caption { max-inline-size: 40em; color: var(--fg-muted); font-size: var(--fs-small); line-height: 1.5; }
.figure--cog { justify-items: center; text-align: center; }
/* A caption that sits low in the frame like a subtitle. */
.subtitle {
  position: absolute;
  inset-inline: 6%;
  inset-block-end: 7%;
  z-index: 3;
  max-inline-size: none;
  margin: 0;
  color: var(--bone);
  font-size: var(--fs-caption);
  line-height: 1.4;
  text-align: center;
  text-shadow: 0 1px 2px var(--black), 0 0 .75rem var(--black-a85);
  text-wrap: balance;
}
.subtitle--free { position: static; inset: auto; font-weight: var(--fw-light); letter-spacing: var(--tracking-light); text-shadow: none; }

/* Tilt toward the pointer ([data-tilt]): core.js adds the moving highlight. */
.tilt-shine { position: absolute; inset: 0; z-index: 4; background: radial-gradient(circle at var(--sx, 50%) var(--sy, 0%), rgb(242 236 230 / .16), rgb(242 236 230 / 0) 58%); opacity: var(--so, 0); pointer-events: none; transition: opacity var(--dur-3) ease; }

/* ─────────────────────────────────── 11 Posters, medals, counted numbers ── */

/* A film poster for a coming service day ("Coming soon"): tall card, slate, cog-framed picture or emblem,
   title, date and place, the sign-up action. */
.poster {
  position: relative;
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: var(--space-m);
  padding: clamp(1.25rem, 1rem + 1.4vw, 2rem);
  border: 1px solid var(--line);
  background: var(--night);
  color: var(--fg);
}
.poster__art { display: grid; place-items: center; padding-block: .5rem; }
.poster__art > .frame { inline-size: min(78%, 15rem); }
.poster__art > :is(.wheel, img) { inline-size: min(70%, 13rem); color: var(--cranberry); }
.poster__body { display: grid; gap: .75rem; align-content: start; }
.poster__title { font-size: calc(clamp(1.5625rem, 1.4rem + .74vw, 2.0625rem) * var(--display-scale)); font-weight: var(--fw-display); line-height: 1.12; }
.poster__when { color: var(--heading); font-family: var(--font-display); font-size: var(--fs-lead); font-weight: var(--fw-light); line-height: 1.3; }
.poster__facts { display: grid; gap: .4rem; color: var(--fg-muted); }
.poster__facts > li { display: flex; align-items: flex-start; gap: .6rem; }
.poster__facts .icon { inline-size: 1.25rem; block-size: 1.25rem; margin-block-start: .2em; color: var(--cranberry-lit); }
.poster__foot { display: grid; gap: .75rem; justify-items: start; }
.poster--tbc .poster__art > .wheel { color: var(--night-2); }

/* A medal: a white disc with a cog edge on a cranberry ribbon. Awards only. */
.medal { display: inline-grid; justify-items: center; max-inline-size: 13rem; text-align: center; }
.medal__ribbon { display: block; inline-size: calc(var(--medal, 7rem) * .36); block-size: calc(var(--medal, 7rem) * .5); margin-block-end: calc(var(--medal, 7rem) * -.14); background: var(--cranberry); }
.medal__disc {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: var(--medal, 7rem);
  aspect-ratio: 1;
  background: var(--white);
  color: var(--black);
  -webkit-mask: var(--wheel-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat;
  mask: var(--wheel-mask) center / calc(100% - 2px) calc(100% - 2px) no-repeat;
}
.medal__disc::before { content: ""; position: absolute; inset: 15%; border: 1px solid var(--cranberry); border-radius: 50%; }
.medal__disc::after { content: ""; position: absolute; inset: 18.5%; border: 1px solid rgb(11 8 9 / .3); border-radius: 50%; }
.medal__years { position: relative; font-size: var(--fs-slate); font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums lining-nums; }   /* lint-ok: engraving on a medal, black on white 20:1 */
.medal__name { margin-block-start: .75rem; font-weight: var(--fw-strong); line-height: var(--lh-ui); max-inline-size: none; }
.medal__kind { color: var(--fg-muted); font-size: 1rem; line-height: var(--lh-ui); max-inline-size: none; }
.medal--sm { --medal: 5rem; }
.medal--lg { --medal: 9.5rem; }

/* A true number that counts up (data-count), with the label that follows it: heavy figure, light label. */
.stat { display: grid; gap: .25rem; }
.stat__num { max-inline-size: none; font-family: var(--font-display); font-size: var(--fs-stat); font-weight: var(--fw-display); line-height: 1; letter-spacing: var(--tracking-display); font-variant-numeric: tabular-nums lining-nums; color: var(--heading); }
.stat__label { color: var(--fg-muted); font-size: var(--fs-lead); font-weight: var(--fw-light); line-height: 1.35; max-inline-size: 16em; }
.stat--lit .stat__num { color: var(--cranberry-lit); }

/* ───────────────────────────────────── 12 Panels, lists, dated entries ── */
.panel { position: relative; padding: clamp(1.25rem, 1rem + 1.6vw, 2.25rem); border: 1px solid var(--rule); border-radius: var(--r-panel); background: var(--row); color: var(--fg); }
.panel--raised { background: var(--night-2); }
.panel--line { background: transparent; }
.panel--lit { background: var(--bg); border-color: transparent; }
.panel--flush { padding: 0; overflow: hidden; }
.panel > * + * { margin-block-start: var(--space-s); }

/* A list whose marker is one tooth of the wheel. Never a bare bullet. */
.tooth-list { display: grid; gap: .6rem; }
.tooth-list > li { position: relative; padding-inline-start: 1.7em; }
.tooth-list > li::before { content: ""; position: absolute; inset-inline-start: 0; inset-block-start: .42em; }
.tooth-list--white > li::before { background: var(--white); }

/* A scale with a tooth for each tick: <ol class="tick-scale" role="list"><li>1988</li>…</ol> */
.tick-scale { display: flex; justify-content: space-between; gap: .5rem; padding-block-start: .9rem; border-block-start: 1px solid var(--line-strong); color: var(--fg-muted); font-size: var(--fs-slate); font-weight: var(--fw-slate); font-variant-numeric: tabular-nums lining-nums; }   /* lint-ok: slate furniture */
.tick-scale > li { position: relative; }
.tick-scale > li::before { content: ""; position: absolute; inset-inline-start: 0; inset-block-end: calc(100% + .9rem); inline-size: calc(.55rem * var(--tooth-ratio, 1.2)); block-size: .55rem; background: var(--ash); -webkit-mask: var(--tooth-mask) center / 100% 100% no-repeat; mask: var(--tooth-mask) center / 100% 100% no-repeat; }
.tick-scale > li[aria-current]::before { background: var(--cranberry); }
.tick-scale > li[aria-current] { color: var(--bone); }

/* A dated entry of the record: slate (the year), a title, a line or two. */
.entry { display: grid; gap: .5rem; padding-block: 1.5rem; border-block-start: 1px solid var(--rule); }
.entry__title { font-size: var(--fs-sub); }
.entry__text { color: var(--fg-muted); }
@media (min-width: 48rem) {
  .entry { grid-template-columns: 12rem minmax(0, 1fr); column-gap: 2rem; }
  .entry > .slate { align-self: start; margin-block-start: .45em; }
  .entry > :not(.slate) { grid-column: 2; }
}

/* A plain calendar line (the meeting, World Rotaract Week): the date in the slate line, then what. */
.calendar-line { display: grid; gap: .25rem 1.5rem; padding-block: 1rem; border-block-start: 1px solid var(--rule); }
@media (min-width: 40rem) { .calendar-line { grid-template-columns: minmax(14rem, auto) minmax(0, 1fr); align-items: baseline; } }

/* ───────────────────────────────────────────────────── 13 FAQ rows ──
   Native <details>. core.js animates the height; the small cog turns one window (60 degrees). */
.faq { border-block-end: 1px solid var(--rule); }
.faq__item { border-block-start: 1px solid var(--rule); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  min-block-size: 4rem;
  padding-block: 1rem;
  font-family: var(--font-display);
  font-size: calc(clamp(1.1875rem, 1.12rem + .32vw, 1.375rem) * var(--display-scale));
  font-weight: var(--fw-title);
  line-height: var(--lh-sub);
  letter-spacing: var(--tracking-sub);
}
.faq__mark { flex: none; inline-size: 1.75rem; block-size: 1.75rem; color: var(--cranberry); transition: rotate var(--dur-4) var(--ease-out), color var(--dur-2) ease; }
.faq__mark .wheel { inline-size: 100%; block-size: 100%; }
.faq__item[open]:not(.is-closing) .faq__mark { rotate: 60deg; color: var(--cranberry-lit); }
.faq__a { overflow: hidden; }
.faq__a > :last-child { padding-block-end: 1.5rem; }
.faq__a > * + * { margin-block-start: .75em; }
.faq__q:active, .faq__q.is-pressed { color: var(--cranberry-lit); }
@media (hover: hover) and (pointer: fine) { .faq__q:hover .faq__mark { rotate: 30deg; } .faq__item[open]:not(.is-closing) .faq__q:hover .faq__mark { rotate: 90deg; } }

/* ────────────────────────────────────────────────── 14 Forms on dark ──
   Night-coloured fields with bone text, large labels above, errors in words beside the field. */
.form { display: grid; gap: var(--space-m); max-inline-size: 38rem; }
.field { position: relative; display: grid; gap: .5rem; }
.field__label { color: var(--fg); font-size: var(--fs-lead); font-weight: var(--fw-strong); line-height: var(--lh-ui); }
.field--choices > legend { padding: 0 0 .5rem; }   /* a legend is not a grid item: the fieldset's gap passes it by */
.field__optional { color: var(--fg-muted); font-size: 1rem; font-weight: var(--fw-light); }
.field__hint { max-inline-size: none; color: var(--fg-muted); font-size: 1rem; line-height: 1.5; }
.field__input {
  inline-size: 100%;
  min-block-size: 3.25rem;
  padding: .75rem 1rem;
  border: 1px solid var(--field-line);
  border-radius: var(--r-field);
  background: var(--field);
  color: var(--fg);
  font-size: var(--fs-body);
  line-height: var(--lh-ui);
  transition: border-color var(--dur-2) ease, background-color var(--dur-2) ease;
  -webkit-appearance: none;
  appearance: none;
}
textarea.field__input { min-block-size: 8.5rem; line-height: var(--lh-text); resize: vertical; }
.field__input::placeholder { color: var(--ash); opacity: 1; }
.field__input:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-color: var(--bone); }
.field__input:-webkit-autofill { -webkit-text-fill-color: var(--bone); box-shadow: 0 0 0 100vmax var(--night-2) inset; caret-color: var(--bone); }
.field.is-invalid .field__input, .field.is-invalid .check__box { border-color: var(--cranberry-lit); box-shadow: 0 0 0 1px var(--cranberry-lit); }
.field__error { display: flex; align-items: baseline; gap: .6em; max-inline-size: none; color: var(--error); font-size: 1rem; font-weight: var(--fw-strong); line-height: 1.4; }
.field__error::before { content: ""; background: var(--cranberry-lit); }
@media (hover: hover) and (pointer: fine) { .field__input:hover { border-color: var(--bone); } }

/* Choices: pills that hold a radio or a checkbox. A radio is the ring (chosen: the ring with its core);
   a checkbox is the ring, and ticked it is the keyway "C". The chosen pill is cranberry as well. */
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip { position: relative; display: inline-flex; }
.chip > input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; margin: 0; opacity: 0; cursor: pointer; }
.chip > span {
  display: inline-flex;
  align-items: center;
  gap: .55em;
  min-block-size: var(--target);
  padding: .45rem 1.1rem .45rem .8rem;
  border: 1px solid var(--field-line);
  border-radius: var(--r-full);
  color: var(--fg);
  font-size: 1rem;
  font-weight: var(--fw-strong);
  line-height: var(--lh-ui);
  transition: background-color var(--dur-2) ease, border-color var(--dur-2) ease;
}
.chip > span::before { content: ""; flex: none; box-sizing: border-box; inline-size: 1.1em; block-size: 1.1em; border: 2px solid currentColor; border-radius: 50%; opacity: .7; }
.chip > input:checked + span { border-color: var(--cranberry); background: var(--cranberry); color: var(--white); }
.chip > input:checked + span::before { opacity: 1; }
.chip > input[type="radio"]:checked + span::before { padding: 2px; background: currentColor; background-clip: content-box; }
.chip > input[type="checkbox"]:checked + span::before { border: 0; border-radius: 0; background: currentColor; -webkit-mask: var(--keyway-mask) center / contain no-repeat; mask: var(--keyway-mask) center / contain no-repeat; }
.chip > input:focus-visible + span { outline: 2px solid var(--focus); outline-offset: 3px; }
.chip.is-pressed > span { background: var(--bone-a10); }
@media (hover: hover) and (pointer: fine) { .chip > input:not(:checked):hover + span { border-color: var(--bone); } }

/* The consent tick: ticked, the box is cranberry and holds the keyway "C". */
.check { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: .875rem; min-block-size: var(--target); cursor: pointer; }
.check__input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; margin: 0; opacity: 0; cursor: pointer; }   /* the whole line is the target */
.check__box { display: grid; place-items: center; inline-size: 1.75rem; block-size: 1.75rem; margin-block-start: .1em; border: 1px solid var(--field-line); border-radius: 50%; background: var(--field); color: var(--white); transition: background-color var(--dur-2) ease, border-color var(--dur-2) ease; }
.check__box .keyway { inline-size: 1.05rem; block-size: 1.05rem; opacity: 0; transition: opacity var(--dur-2) ease; }
.check__input:checked + .check__box { border-color: var(--cranberry); background: var(--cranberry); }
.check__input:checked + .check__box .keyway { opacity: 1; }
.check__input:focus-visible + .check__box { outline: 2px solid var(--focus); outline-offset: 3px; }
.check__label { line-height: 1.5; }
.form__note, .form__pics { color: var(--fg-muted); font-size: 1rem; line-height: 1.5; }
/* Preview mode: the form says, before anybody presses the button, that nothing is sent (form.html writes it). */
/* (Its lines are balanced: where the sentence takes two lines they are two of a length, never "is sent." alone.) */
.form__preview { display: flex; align-items: flex-start; gap: .6rem; max-inline-size: none; color: var(--fg); font-size: 1rem; font-weight: var(--fw-strong); line-height: 1.5; text-wrap: balance; }
.form__preview .icon { inline-size: 1.25rem; block-size: 1.25rem; margin-block-start: .1em; color: var(--accent); }
/* Scripts off: the button is disabled, nothing can be sent, and this sentence says so beside it. The second
   copy (--late) is for scripts that are on but never took the form over. */
.form__noscript { flex-basis: 100%; max-inline-size: none; padding-inline-start: 1rem; border-inline-start: 3px solid var(--cranberry); color: var(--fg); font-size: 1rem; font-weight: var(--fw-strong); line-height: 1.5; }
.form__noscript--late { display: none; }
html.rac-failsafe .form:not(.is-ready) .form__noscript--late { display: block; }
.form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
.form__status { display: grid; gap: .25rem; padding: 1rem 1.25rem; border-inline-start: 3px solid var(--cranberry); background: var(--night-2); }
.form__status:focus { outline: none; }
.form__status strong { font-family: var(--font-display); font-size: var(--fs-sub); font-weight: var(--fw-title); line-height: var(--lh-sub); }
.form.is-sending [type="submit"] { cursor: progress; }
.form.is-sending [type="submit"]::before { display: none; }
.form.is-sending [type="submit"] .loading-mark { display: inline-block; }

/* ───────────────────────────────────────────── 15 The turn-over card ──
   A card that turns over on tap, click or Enter (data-turn-card). Both faces are in the page in reading
   order; without scripts they simply stand one above the other. No links inside: the whole card is the button.
   It turns in two halves (the front to its edge, then the back from its edge), so no browser has to hide
   the back of anything. */
.turn-card { position: relative; perspective: 70rem; }
.turn-card__inner { position: relative; display: grid; block-size: 100%; }
.turn-card__face {
  grid-area: 1 / 1;
  display: grid;
  align-content: end;
  gap: .5rem;
  min-block-size: var(--card-h, 19rem);
  padding: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  border: 1px solid var(--line);
  background: var(--night);
  transition: transform calc(var(--dur-4) / 2) ease-out calc(var(--dur-4) / 2);
}
.turn-card__face--back { align-content: center; background: var(--night-2); transform: rotateY(-90deg); transition: transform calc(var(--dur-4) / 2) ease-in 0s; }
.turn-card.is-turned .turn-card__face--front { transform: rotateY(90deg); transition: transform calc(var(--dur-4) / 2) ease-in 0s; }
.turn-card.is-turned .turn-card__face--back { transform: none; transition: transform calc(var(--dur-4) / 2) ease-out calc(var(--dur-4) / 2); }
.turn-card__mono { inline-size: 3.5rem; block-size: 3.5rem; margin-block-end: auto; color: var(--cranberry); }
.turn-card__mono .wheel { inline-size: 100%; block-size: 100%; }
.turn-card__role { font-size: var(--fs-sub); }
.turn-card__name { color: var(--fg-muted); font-weight: var(--fw-light); font-size: var(--fs-lead); max-inline-size: none; }
.turn-card__btn { position: absolute; inset: 0; z-index: 2; inline-size: 100%; block-size: 100%; cursor: pointer; }
/* The whole card is the button. A face turned edge-on (and any face of a tilted card) still owns a sliver along
   the axis of the turn, and Chromium gives that sliver the click instead of the button lying over it: a click
   in the very middle did nothing. The faces hold no controls, so with scripts on they take no clicks at all. */
html.js .turn-card:not(.turn-card--seat) .turn-card__face { pointer-events: none; }
.turn-card__btn .icon { position: absolute; inset-block-start: 1rem; inset-inline-end: 1rem; color: var(--ash); transition: rotate var(--dur-4) var(--ease-out), color var(--dur-2) ease; }
.turn-card.is-turned .turn-card__btn .icon { rotate: 180deg; color: var(--cranberry-lit); }
.turn-card__btn:focus-visible { outline-offset: -4px; }
@media (hover: hover) and (pointer: fine) { .turn-card__btn:hover .icon { color: var(--bone); } }
@media (prefers-reduced-motion: reduce) { .turn-card__face, .turn-card.is-turned .turn-card__face { transition: none; } }
html:not(.js) .turn-card { perspective: none; }
html:not(.js) .turn-card__inner { display: block; }
html:not(.js) .turn-card__face { min-block-size: 0; transform: none; }
html:not(.js) .turn-card__face--back { border-block-start: 0; }
html:not(.js) .turn-card__btn { display: none; }
/* The open seat: the same card, but a link (no turning). */
.turn-card--seat { display: block; color: inherit; text-decoration: none; }
.turn-card--seat .turn-card__face { border-style: dashed; border-color: var(--line-strong); background: transparent; transform: none; }
.turn-card--seat .turn-card__mono { color: var(--ash); }

/* ─────────────────────────────────────────── 16 The countdown shell ──
   Days, hours, minutes, seconds: light figures with tabular digits. The signature builder's script fills
   the numbers and sets data-state: "running" shows the units, "tbc" shows the date-to-be-confirmed line.
   Until then, and without scripts, the plain date line is what is shown. */
.countdown { display: grid; gap: var(--space-s); justify-items: start; }
.countdown__units { display: none; flex-wrap: wrap; gap: 1rem clamp(1rem, 3vw, 2.75rem); }
.countdown__unit { display: grid; gap: .35rem; }
.countdown__num { color: var(--heading); font-family: var(--font-display); font-size: var(--fs-count); font-weight: var(--fw-light); line-height: 1; letter-spacing: var(--tracking-display); font-variant-numeric: tabular-nums lining-nums; }
.countdown__name { color: var(--fg-muted); font-size: var(--fs-slate); font-weight: var(--fw-slate); line-height: var(--lh-ui); letter-spacing: var(--tracking-slate); text-transform: var(--case-slate); }   /* lint-ok: slate furniture */
.countdown__date, .countdown__tbc { font-family: var(--font-display); font-size: var(--fs-sub); font-weight: var(--fw-light); line-height: var(--lh-sub); }
.countdown__tbc { display: none; }
.countdown__escapement { inline-size: 4rem; aspect-ratio: 1; color: var(--cranberry); }
.countdown[data-state="running"] .countdown__units { display: flex; }
.countdown[data-state="running"] .countdown__date { color: var(--fg-muted); font-family: var(--font-text); font-size: var(--fs-body); font-weight: var(--fw-text); line-height: var(--lh-text); }
.countdown[data-state="tbc"] .countdown__tbc { display: block; }
.countdown[data-state="tbc"] .countdown__date { display: none; }

/* ────────────────────────────────────────────── 17 The credits roll ──
   Role on one side, light; name on the other, heavy; centred on the gap. With data-credits and motion it
   rolls with the scroll inside a soft-edged window; otherwise it is a plain list. */
.credits { position: relative; }
.credits__roll { display: grid; gap: 1.1rem; margin: 0; }
.credits__row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: baseline; gap: 1.5rem; }
.credits__row > dt { color: var(--fg-muted); font-size: var(--fs-slate); font-weight: var(--fw-slate); line-height: var(--lh-ui); letter-spacing: var(--tracking-slate); text-align: end; text-transform: var(--case-slate); }   /* lint-ok: slate furniture */
.credits__row > dd { margin: 0; font-family: var(--font-display); font-size: var(--fs-sub); font-weight: var(--fw-title); line-height: var(--lh-sub); text-align: start; }
.credits__row--solo { grid-template-columns: minmax(0, 1fr); padding-block: 1rem; }
.credits__row--solo > dd { font-size: var(--fs-section); font-weight: var(--fw-display); line-height: var(--lh-display); text-align: center; }
.credits__row--note { grid-template-columns: minmax(0, 1fr); }
.credits__row--note > dd { grid-column: 1 / -1; color: var(--fg-muted); font-family: var(--font-text); font-size: var(--fs-small); font-weight: var(--fw-light); line-height: 1.5; text-align: center; }
.credits.is-rolling {
  block-size: min(64svh, 32rem);
  overflow: hidden;
  -webkit-mask: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
  mask: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
}

/* ─────────────────────────────────────────────── 18 Motion helpers ── */

/* Line and word reveals (core.js splits the text; never by character). */
.rac-line { display: block; overflow: hidden; padding-block: var(--mask-pad); margin-block: calc(var(--mask-pad) * -1); }
.rac-line__in { display: block; }
.rac-word { display: inline-block; overflow: hidden; padding-block: var(--mask-pad); margin-block: calc(var(--mask-pad) * -1); vertical-align: top; }
.rac-word__in { display: inline-block; }

/* The cog cursor: a small wheel that follows a fine pointer, turns with it, and meshes on buttons and
   links. The system cursor stays; over text fields the cog steps aside. Never on touch. */
.cog-cursor {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: 0;
  z-index: var(--z-cursor);
  inline-size: 1.75rem;
  block-size: 1.75rem;
  margin: -.875rem 0 0 -.875rem;
  color: var(--cranberry-lit);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-3) ease, color var(--dur-2) ease;
}
.cog-cursor.is-on { opacity: .85; }
.cog-cursor.is-meshed { color: var(--white); }
.cog-cursor.is-away { opacity: 0; }
.cog-cursor svg { display: block; inline-size: 100%; block-size: 100%; fill: currentColor; }

/* Press: what a finger gets where a mouse gets hover (core.js sets .is-pressed on touch). */
.btn--primary.is-pressed::before { rotate: 120deg; }
.site-nav__link.is-pressed, .site-footer__links a.is-pressed, .hud__btn.is-pressed, .link.is-pressed { color: var(--cranberry-lit); }
.poster.is-pressed, .panel.is-pressed { border-color: var(--line-strong); }

}   /* end of @layer components */
