/* ==========================================================================
   Minimal Cozy — Conway C. Liao
   Editorial design system: 12-col grid, TWK Lausanne (sans) + TWK Ghost (serif),
   scroll-driven colour atmosphere.
   ========================================================================== */

/* Fonts ------------------------------------------------------------------- */
@font-face { font-family: 'Lausanne'; src: url('/assets/fonts/TWKLausanne-300.woff2') format('woff2'); font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: 'Lausanne'; src: url('/assets/fonts/TWKLausanne-300Italic.woff2') format('woff2'); font-weight: 300; font-style: italic; font-display: swap; }
@font-face { font-family: 'Lausanne'; src: url('/assets/fonts/TWKLausanne-400.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Lausanne'; src: url('/assets/fonts/TWKLausanne-400Italic.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'Lausanne'; src: url('/assets/fonts/TWKLausanne-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: 'Ghost'; src: url('/assets/fonts/TWKGhost-Thin.woff2') format('woff2'); font-weight: 100; font-style: normal; font-display: swap; }
@font-face { font-family: 'Ghost'; src: url('/assets/fonts/TWKGhost-Light.woff2') format('woff2'); font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: 'Ghost'; src: url('/assets/fonts/TWKGhost-LightItalic.woff2') format('woff2'); font-weight: 300; font-style: italic; font-display: swap; }
@font-face { font-family: 'Ghost'; src: url('/assets/fonts/TWKGhost-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Ghost'; src: url('/assets/fonts/TWKGhost-Italic.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }

/* Tokens ------------------------------------------------------------------ */
:root {
  /* The colours the stylesheet itself uses (the section tones live in site.json → tones) */
  --paper:    #F3F1EC;
  --ink:      #1E1B1A;
  --mauve:    #CDB9C6;
  --saffron:  #EFB04A;

  /* Live atmosphere values (overwritten every frame by motion.js) */
  --bg: var(--paper);
  --fg: var(--ink);
  --g1: var(--paper);
  --g2: var(--paper);
  --g3: var(--paper);
  --shift: 0;
  --muted: color-mix(in srgb, var(--fg) 55%, transparent);
  --rule:  color-mix(in srgb, var(--fg) 22%, transparent);

  /* Type */
  /* CJK fallbacks so Chinese characters (e.g. 廖晟瑋) render in a matching style */
  --sans: 'Lausanne', 'Helvetica Neue', Helvetica, Arial, 'PingFang TC', 'Noto Sans TC', 'Microsoft JhengHei', sans-serif;
  --serif: 'Ghost', 'Times New Roman', Georgia, 'Songti TC', 'Noto Serif TC', 'PMingLiU', serif;
  --t-label: 11px;
  --t-small: 13px;
  --t-body: clamp(16px, 1.05vw + 6px, 18px);
  --t-lead: clamp(21px, 1.6vw + 6px, 30px);
  --t-h3: clamp(26px, 2.4vw + 6px, 44px);
  --t-statement: clamp(34px, 4.6vw, 84px);
  --t-display: clamp(56px, 10.4vw, 200px);
  --t-mega: clamp(160px, 30vw, 520px);

  /* Grid */
  --cols: 12;
  --margin: clamp(16px, 2.6vw, 44px);
  --gutter: clamp(12px, 1.6vw, 24px);
  --header-h: 64px;

  /* Rhythm */
  --space-s: clamp(48px, 6vw, 96px);
  --space-m: clamp(80px, 10vw, 180px);
  --space-l: clamp(120px, 16vw, 280px);

  /* Grain — size and amount come from Site settings → Grain */
  --grain-svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 220' preserveAspectRatio='none'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --grain-size: 220px;
  --grain-opacity: .14;

  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-inout: cubic-bezier(.65, 0, .35, 1);
}

/* Base -------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Phones and tablets scroll but don't pinch or double-tap zoom (with the viewport tag; app.js covers Safari). */
@media (pointer: coarse) {
  html { touch-action: pan-x pan-y; }
  .site-foot__col a { padding-block: 6px; } /* a finger's row */
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-weight: 300;
  font-size: var(--t-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
h1, h2, h3, h4 { margin: 0; font-weight: inherit; }
figure { margin: 0; }
::selection { background: var(--saffron); color: var(--ink); }
:focus-visible { outline: 1px solid currentColor; outline-offset: 4px; }

.label {
  font-family: var(--sans);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1.35;
}
.muted { color: var(--muted); }

/* Grid -------------------------------------------------------------------- */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: var(--gutter);
  padding-inline: var(--margin);
}
.col { grid-column: var(--start, auto) / span var(--span, 12); min-width: 0; }

@media (max-width: 760px) {
  :root { --cols: 6; --header-h: 56px; }
}

.grid-overlay { position: fixed; inset: 0; pointer-events: none; z-index: 90; display: none; }
.grid-overlay .grid { height: 100%; }
html.show-grid .grid-overlay { display: block; }
.grid-overlay .grid > span { background: rgba(239, 176, 74, .12); border-inline: 1px solid rgba(239, 176, 74, .35); }

/* Atmosphere -------------------------------------------------------------- */
/* The field and the orb drift as the page scrolls by moving (transform), not by being painted again, so a phone's
   GPU only moves them: only a change of colours between sections repaints. */
.atmosphere { position: fixed; inset: 0; z-index: -1; overflow: hidden; background: var(--bg); }
.atmosphere__field {
  /* The whole gradient, 1.6× a field 1.2× the screen, slides up through it over the page (--shift 0 → 1) */
  position: absolute; left: 0; right: 0; top: -10%; height: 192%;
  background: linear-gradient(180deg, var(--g1) 0%, var(--g2) 50%, var(--g3) 100%);
  transform: translate3d(0, calc(var(--shift) * -37.5%), 0);
  will-change: transform;
}
.atmosphere__orb {
  position: absolute;
  width: 90vmax; height: 90vmax;
  left: 50%; top: 50%;
  border-radius: 50%;
  /* As soft as the old 40px blur of a fade to 70%, in the gradient's own stops: a blur that size is the costliest
     thing a phone can be asked to draw. */
  background: radial-gradient(closest-side, color-mix(in srgb, var(--g2) 86%, transparent), color-mix(in srgb, var(--g2) 80%, transparent) 10%, color-mix(in srgb, var(--g2) 69%, transparent) 20%, color-mix(in srgb, var(--g2) 42%, transparent) 40%, color-mix(in srgb, var(--g2) 14%, transparent) 60%, color-mix(in srgb, var(--g2) 4%, transparent) 70%, transparent 82%);
  opacity: .55;
  transform: translate3d(calc(-50% + (var(--shift) - .5) * 40vw), calc(-50% + (var(--shift) - .5) * -30vh), 0);
  will-change: transform;
}
.atmosphere__grain {
  position: absolute; inset: 0;
  opacity: var(--grain-opacity);
  mix-blend-mode: overlay;
  background-image: var(--grain-svg);
  background-size: var(--grain-size);
}

/* Masthead + folio -------------------------------------------------------- */
.masthead {
  position: fixed; inset: 0 0 auto; z-index: 50;
  height: var(--header-h);
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: var(--gutter);
  align-items: baseline; /* name, role and nav share a baseline, whatever their sizes */
  align-content: center;
  padding-inline: var(--margin);
  color: var(--fg);
  transition: transform .6s var(--ease-out);
}
.masthead.is-hidden { transform: translateY(-100%); }
/* Tabbing into a tucked-away masthead brings it back, so focus is never off-screen. */
.masthead.is-hidden:focus-within { transform: none; }
/* Over the taste chart's places (`is-solid`, from embeds.js) the masthead takes the section's ground, grain
   and all, so the rows passing under it don't run through the name. Only the opacity eases; the colour
   follows --bg as it blends between sections. */
.masthead::before, .masthead::after { content: ''; position: absolute; inset: 0; z-index: -1; opacity: 0; pointer-events: none; transition: opacity .4s var(--ease-out); }
.masthead::before { background: var(--bg); }
.masthead::after { mix-blend-mode: overlay; background-image: var(--grain-svg); background-size: var(--grain-size); }
.masthead.is-solid::before { opacity: 1; }
.masthead.is-solid::after { opacity: var(--grain-opacity); }
.masthead__name { grid-column: 1 / span 4; font-family: var(--serif); font-weight: 400; font-size: 19px; letter-spacing: -.005em; white-space: nowrap; }
.masthead__role { grid-column: 6 / span 3; }
.masthead__nav { grid-column: 9 / -1; display: flex; justify-content: flex-end; gap: clamp(14px, 2vw, 32px); }
.masthead__nav a { font-size: var(--t-small); font-weight: 400; position: relative; padding-block: 4px; }
.masthead__nav a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right; transition: transform .5s var(--ease-out);
}
.masthead__nav a:hover::after, .masthead__nav a[aria-current='page']::after, .nav-item.is-within > .nav-item__top::after { transform: scaleX(1); transform-origin: left; }
/* An item stays underlined while its dropdown is open (the pointer is down in the panel, not on it). */
.nav-item:hover > .nav-item__top::after, .nav-item:focus-within > .nav-item__top::after { transform: scaleX(1); transform-origin: left; }
/* Sub-links: on hover or keyboard focus a frosted field wipes down under the item (it blurs whatever is
   behind it, so it reads on any section, hero media included), and each link rises out of a mask in turn;
   it folds back up on the way out. The tint is the text colour inverted, so it always deepens the contrast. */
.nav-item { position: relative; display: flex; }
.nav-item__top { font-size: var(--t-small); font-weight: 400; position: relative; padding-block: 4px; cursor: default; }
a.nav-item__top { cursor: pointer; }
span.nav-item__top::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform .5s var(--ease-out); }
.nav-sub { position: absolute; top: 100%; left: 50%; transform: translateX(-50%); padding-top: 6px; visibility: hidden; transition: visibility 0s .5s; }
.nav-sub__panel { display: grid; justify-items: center; text-align: center; padding: 10px 18px 8px; /* even space around the caps */ background: color-mix(in srgb, var(--fg) 8%, transparent); background: rgb(from var(--fg) calc(255 - r) calc(255 - g) calc(255 - b) / .3); -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); clip-path: inset(0 0 100% 0); transition: clip-path .45s var(--ease-inout); }
/* Centred under the item, unless that would run off the page's right edge. */
.nav-sub.is-end { left: auto; right: -18px; transform: none; }
.nav-sub.is-end .nav-sub__panel { justify-items: end; text-align: right; }
.nav-sub__mask { display: block; overflow: hidden; padding-bottom: .1em; white-space: nowrap; }
.nav-sub__text { display: block; transform: translateY(110%); transition: transform .3s var(--ease-out); }
.nav-item:hover .nav-sub, .nav-item:focus-within .nav-sub { visibility: visible; transition: none; }
.nav-item:hover .nav-sub__panel, .nav-item:focus-within .nav-sub__panel { clip-path: inset(0); transition: clip-path .6s var(--ease-inout); }
.nav-item:hover .nav-sub__text, .nav-item:focus-within .nav-sub__text { transform: none; transition: transform .8s var(--ease-out) calc(.14s + var(--j) * 60ms); }
/* Closed by Escape, until focus leaves the item or the mouse is used. */
.nav-item.is-quiet .nav-sub { visibility: hidden; transition: none; }

/* Phone menu: the nav folds into a two-line button that crosses into an X as a full-screen menu wipes
   down on the gradient chosen in Site settings, its links set large in Ghost and rising in turn. */
.masthead__menu, .menu { display: none; }
@media (max-width: 760px) {
  .masthead__nav { display: none; }
  .masthead__menu { grid-column: -2 / -1; justify-self: end; align-self: center; position: relative; display: block; width: 44px; height: 44px; margin-right: -11px; padding: 0; border: 0; background: none; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .masthead__menu span { position: absolute; left: 11px; right: 11px; height: 1.5px; background: currentColor; transition: top .5s var(--ease-out), transform .5s var(--ease-out); }
  .masthead__menu span:first-child { top: 17.5px; }
  .masthead__menu span:last-child { top: 25px; }
  .menu-open .masthead__menu span:first-child { top: 21.25px; transform: rotate(45deg); }
  .menu-open .masthead__menu span:last-child { top: 21.25px; transform: rotate(-45deg); }
  .menu-open, .menu-open body { overflow: hidden; }
  .menu-open .masthead { color: var(--menu-fg); transform: none; transition: color .4s .2s; }
  .menu-open .masthead::before, .menu-open .masthead::after { opacity: 0; }
  .menu-open .folio { opacity: 0; transition: opacity .3s; }
  .menu {
    position: fixed; inset: 0; z-index: 45;
    display: flex; flex-direction: column; justify-content: space-between;
    padding: calc(var(--header-h) + 40px) var(--margin) calc(24px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, var(--menu-a), var(--menu-b) 55%, var(--menu-c));
    color: var(--menu-fg);
    clip-path: inset(0 0 100% 0);
    visibility: hidden;
    transition: clip-path .7s var(--ease-inout), visibility 0s .7s;
  }
  .menu-open .menu { clip-path: inset(0); visibility: visible; transition: clip-path .7s var(--ease-inout); }
  .menu[hidden] { display: none; }
  .menu__nav { display: grid; gap: 4px; }
  .menu__link { display: flex; align-items: baseline; gap: 16px; }
  .menu__num { flex: none; min-width: 2.8em; opacity: .6; }
  /* The mask is sized by its text, so its room for descenders and italic overhang (.3em below, a little either
     side) is real; the negative margins keep the rows as they were. */
  .menu__mask { display: block; overflow: hidden; font-size: clamp(46px, 13.5vw, 72px); line-height: 1.02; padding: .05em .08em .3em .06em; margin: -.05em -.08em -.3em -.06em; }
  .menu__text { display: block; font-family: var(--serif); font-weight: 300; font-size: inherit; line-height: inherit; letter-spacing: -.025em; transform: translateY(140%); transition: transform .5s var(--ease-out); }
  .menu-open .menu__text { transform: none; transition: transform .9s var(--ease-out) calc(.28s + var(--i) * 70ms); }
  .menu__link[aria-current='page'] .menu__text, .menu__item.is-within .menu__text { font-style: italic; }
  /* Sub-links fold under their item: a thin + (the menu button's lines) opens them and turns to a −. */
  .menu__row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
  button.menu__link { padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
  .menu__toggle { position: relative; flex: none; width: 44px; height: 44px; margin-right: -11px; padding: 0; border: 0; background: none; color: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; opacity: 0; transition: opacity .3s; }
  .menu-open .menu__toggle { opacity: .8; transition: opacity .6s var(--ease-out) calc(.5s + var(--i) * 70ms); }
  .menu__toggle span { position: absolute; left: 13px; right: 13px; top: 21.25px; height: 1.5px; background: currentColor; transition: transform .5s var(--ease-out); }
  .menu__toggle span:last-child { transform: rotate(90deg); }
  .menu__item.is-open .menu__toggle span:last-child { transform: none; }
  .menu__sub { display: grid; grid-template-rows: 0fr; margin-left: calc(2.8em + 16px); transition: grid-template-rows .6s var(--ease-out); }
  .menu__item.is-open .menu__sub { grid-template-rows: 1fr; }
  .menu__sub-inner { min-height: 0; overflow: hidden; display: grid; justify-items: start; gap: 2px; }
  .menu__sub a { position: relative; font-size: 17px; line-height: 1.5; opacity: 0; transform: translateY(8px); transition: opacity .25s, transform .4s var(--ease-out); }
  .menu__sub a::after { content: ''; position: absolute; inset: -7px -8px; } /* a thumb-sized target without spacing the list out */
  .menu__sub a:last-child { margin-bottom: 14px; }
  .menu__item.is-open .menu__sub a { opacity: .8; transform: none; transition: opacity .5s var(--ease-out) calc(.12s + var(--j) * 50ms), transform .7s var(--ease-out) calc(.12s + var(--j) * 50ms); }
  .menu__item.is-open .menu__sub a[aria-current='page'] { opacity: 1; text-decoration: underline; text-underline-offset: .25em; text-decoration-thickness: 1px; }
  .menu__foot { margin: 0; opacity: 0; transition: opacity .3s; }
  .menu-open .menu__foot { opacity: .7; transition: opacity .6s .6s; }
}

.folio {
  position: fixed; inset: auto 0 0; z-index: 50;
  display: flex; justify-content: space-between; align-items: center;
  padding: 0 var(--margin) 18px;
  color: var(--fg);
  pointer-events: none;
}
.folio__section { transition: opacity .4s; }
.folio { transition: opacity .4s; }
.folio.is-off { opacity: 0; }
/* Signed in, on a draft or internal page: a quiet note that visitors don't see it (app.js). */
.private-note {
  position: fixed; left: 50%; bottom: 14px; z-index: 51; transform: translateX(-50%); margin: 0;
  padding: 5px 12px; border-radius: 999px; white-space: nowrap; pointer-events: none;
  background: var(--fg); color: var(--bg);
}

@media (max-width: 760px) {
  .masthead { align-items: center; } /* only the name and the menu button here: centred, not on a baseline */
  .masthead__name { grid-column: 1 / span 3; font-size: 17px; }
  .masthead__role { display: none; }
  .folio { padding-bottom: 12px; }
}

/* Page + transitions ------------------------------------------------------ */
.page { display: block; outline: none; transition: opacity .5s var(--ease-inout); }
.page.is-leaving { opacity: 0; }

.module { position: relative; padding-block: var(--space-m); }
.module[data-spacing='s'] { padding-block: var(--space-s); }
.module[data-spacing='l'] { padding-block: var(--space-l); }
.module[data-spacing='none'] { padding-block: 0; }
.module + .module[data-spacing='tight'] { padding-top: 0; }

/* Eyebrow and aside sit on the title's (last) baseline. */
.module-head { margin-bottom: clamp(32px, 4vw, 64px); align-items: last baseline; }
.module-head__label { grid-column: 1 / span 3; margin: 0; }
.module-head__title { grid-column: 4 / span 7; font-family: var(--serif); font-weight: 300; font-size: var(--t-h3); line-height: 1.05; letter-spacing: -.01em; }
.module-head__aside { grid-column: 11 / span 2; margin: 0; text-align: right; }
@media (max-width: 760px) {
  .module-head > * { text-align: left; }
  .module-head__label { margin-bottom: 12px; }
  .module-head__aside { margin-top: 12px; }
}

/* Type animation primitives ---------------------------------------------- */
/* text-indent must not inherit into each word (it would shift and clip them). Each word's mask reaches .3em below
   its line box for descenders at tight leading, and a little either side for italic overhang; the negative margins
   give that room back, so lines sit as they would unmasked. A word starts further down (140%) to stay hidden. */
.split .w { display: inline-block; overflow: hidden; vertical-align: top; text-indent: 0; padding: .05em .1em .36em .06em; margin: -.05em -.1em -.36em -.06em; }
.cw { display: inline-block; white-space: nowrap; }
.split .w > span { display: inline-block; transform: translate3d(0, 140%, 0); transition: transform 1.1s var(--ease-out); transition-delay: calc(var(--i, 0) * 45ms + var(--d, 0ms)); }
.split.is-in .w > span { transform: none; }

.fade { opacity: 0; transform: translate3d(0, 24px, 0); transition: opacity 1s var(--ease-out), transform 1.2s var(--ease-out); transition-delay: var(--d, 0ms); }
.fade.is-in { opacity: 1; transform: none; }

.scrub .sw { opacity: .16; transition: opacity .25s linear; }
.scrub .sw.on { opacity: 1; }

mark {
  color: inherit;
  background: linear-gradient(90deg, var(--saffron), var(--mauve)) no-repeat 0 88% / 0% .32em;
  transition: background-size 1.4s var(--ease-out) .25s;
  padding-inline: .04em;
}
.is-in mark, .scrub.is-in mark { background-size: 100% .32em; }

/* Rich text from the CMS. Bold steps up one weight rather than synthesising a heavy one. */
p a:not([class]) { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .2em; }
p a:not([class]):hover, p a:not([class])[aria-current='page'] { text-decoration-thickness: 2px; }
strong, b { font-weight: 500; }
u, s { text-decoration-thickness: max(1px, .05em); text-underline-offset: .14em; }
.caps { text-transform: uppercase; letter-spacing: .03em; }
/* Split text sets each word in an inline-block, which an ancestor's decoration can't reach. */
.split u .w > span { text-decoration: underline; text-decoration-thickness: max(1px, .05em); text-underline-offset: .14em; }
.split s .w > span { text-decoration: line-through; text-decoration-thickness: max(1px, .05em); }
.split u s .w > span, .split s u .w > span { text-decoration-line: underline line-through; }

.rule { height: 1px; background: var(--rule); transform-origin: left; transform: scaleX(0); transition: transform 1.4s var(--ease-out); }
.is-in .rule, .rule.is-in { transform: none; }

/* Media + placeholders ---------------------------------------------------- */
.frame { position: relative; overflow: hidden; aspect-ratio: var(--ratio, 3 / 2); background: color-mix(in srgb, var(--fg) 8%, transparent); }
.frame[data-ratio='16:9'] { --ratio: 16 / 9; }
.frame[data-ratio='4:5'] { --ratio: 4 / 5; }
.frame[data-ratio='3:2'] { --ratio: 3 / 2; }
.frame[data-ratio='1:1'] { --ratio: 1; }
.frame[data-ratio='9:16'] { --ratio: 9 / 16; }
.frame[data-ratio='2:3'] { --ratio: 2 / 3; }
.frame > img, .frame > video, .frame > .ph {
  position: absolute; inset: -8% 0; width: 100%; height: 116%; object-fit: cover;
  transform: translate3d(0, calc(var(--px, 0) * 1%), 0) scale(1.02);
  will-change: transform;
}
/* Zoomed in /god's Framing (--zoom, about the focal point --fx --fy, 0–1): the picture's box grows around that
   point, so the point stays put, the frame stays covered through the parallax, and the parallax keeps its travel.
   Sized rather than scaled, so modules that transform their pictures (and reduced motion) keep the zoom. */
.frame > [style*='--zoom'] {
  left: calc((1 - var(--zoom)) * var(--fx) * 100%); top: calc(-8% - (var(--zoom) - 1) * var(--fy) * 116%);
  width: calc(var(--zoom) * 100%); height: calc(var(--zoom) * 116%); max-width: none;
  transform: translate3d(0, calc(var(--px, 0) * 1% / var(--zoom)), 0) scale(1.02);
}
/* Clip the children, not the frame: IntersectionObserver ignores fully clipped targets. */
.reveal > * { clip-path: inset(100% 0 0 0); transition: clip-path 1.4s var(--ease-out); transition-delay: var(--d, 0ms); }
.reveal.is-in > * { clip-path: inset(0 0 0 0); }

.ph { display: block; background: linear-gradient(180deg, var(--ph-a, #4E4C4B), var(--ph-b, #45202A) 55%, var(--ph-c, #CDB9C6)); }
.ph::after {
  content: ''; position: absolute; inset: 0; opacity: calc(var(--grain-opacity) * 1.6); mix-blend-mode: overlay;
  background-image: var(--grain-svg); background-size: calc(var(--grain-size) * .8);
}

.frame__tag { position: absolute; left: 14px; bottom: 12px; z-index: 2; color: rgba(255,255,255,.85); mix-blend-mode: difference; }

.caption { display: flex; justify-content: space-between; gap: 24px; padding-top: 12px; }
.caption > :last-child { text-align: right; }

/* ==========================================================================
   Modules
   ========================================================================== */

/* 01 Hero ----------------------------------------------------------------- */
.m-hero[data-own] { color: var(--fg); --muted: color-mix(in srgb, var(--fg) 70%, transparent); --rule: color-mix(in srgb, var(--fg) 22%, transparent); }
.m-hero { min-height: 100svh; display: flex; flex-direction: column; justify-content: flex-end; padding-block: calc(var(--header-h) + 24px) clamp(56px, 7vw, 96px); overflow: hidden; }
.m-hero[data-align='center'] { justify-content: center; }
.m-hero__media { position: absolute; inset: 0; z-index: -1; }
.m-hero__media .frame { position: absolute; inset: 0; aspect-ratio: auto; height: 100%; }
.m-hero__kicker { grid-column: 1 / span 6; margin-bottom: clamp(20px, 3vw, 40px); }
.m-hero__title {
  grid-column: 1 / -1;
  font-family: var(--serif); font-weight: 300;
  font-size: var(--t-display); line-height: .88; letter-spacing: -.035em;
  transform: translate3d(0, calc(var(--hp, 0) * -18vh), 0);
}
.m-hero[data-size='l'] .m-hero__title { font-size: clamp(52px, 8.4vw, 150px); line-height: .92; }
.m-hero__title em { font-style: italic; }
.m-hero__title .line { display: block; }
.m-hero__title .line:nth-child(2) { padding-left: calc((100% + var(--gutter)) / 12 * 2); transform: translate3d(calc(var(--hp, 0) * 8vw), 0, 0); }
.m-hero__title .line:nth-child(3) { padding-left: calc((100% + var(--gutter)) / 12 * 4); transform: translate3d(calc(var(--hp, 0) * -6vw), 0, 0); }
.m-hero__foot { margin-top: clamp(40px, 6vw, 88px); row-gap: 24px; opacity: calc(1 - var(--hp, 0) * 2.2); }
.m-hero__intro { grid-column: 7 / span 5; font-size: var(--t-lead); line-height: 1.3; }
.m-hero__meta { grid-column: 1 / span 5; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px var(--gutter); align-content: end; }
.m-hero__meta dt { color: var(--muted); }
.m-hero__meta dd { margin: 2px 0 0; font-size: var(--t-small); font-weight: 400; }
@media (max-width: 760px) {
  .m-hero__title .line:nth-child(n) { padding-left: 0; }
  .m-hero__title .line:nth-child(2) { padding-left: 12vw; }
  .m-hero__intro { order: -1; }
}

/* 02 Chapter -------------------------------------------------------------- */
.m-chapter { min-height: 100svh; display: grid; align-content: space-between; padding-block: calc(var(--header-h) + 24px) clamp(56px, 7vw, 96px); overflow: hidden; }
.m-chapter[data-height='half'] { min-height: 64svh; }
.m-chapter__top { align-items: start; }
.m-chapter__label { grid-column: 1 / span 3; }
.m-chapter__aside { grid-column: 10 / -1; text-align: right; }
.m-chapter__num {
  position: absolute; right: calc(var(--margin) - .06em); top: 50%;
  font-family: var(--serif); font-weight: 100; font-size: var(--t-mega); line-height: .8; letter-spacing: -.05em;
  transform: translate3d(0, calc(-50% + var(--cp, 0) * -20vh), 0);
  opacity: .9; pointer-events: none; font-variant-numeric: lining-nums;
}
.m-chapter__title { grid-column: 1 / span 9; font-family: var(--serif); font-weight: 300; font-size: clamp(48px, 7.6vw, 140px); line-height: .92; letter-spacing: -.03em; }
.m-chapter__title sup { font-family: var(--sans); font-size: .22em; letter-spacing: 0; vertical-align: top; position: relative; top: .35em; margin-left: .2em; }
.m-chapter__sub { grid-column: 1 / span 5; margin-top: 28px; font-size: var(--t-lead); line-height: 1.3; }

/* 03 Text ----------------------------------------------------------------- */
.m-text__label { grid-column: 1 / span 3; padding-top: .6em; }
.m-text__body { grid-column: var(--start, 4) / span var(--span, 8); }
.m-text[data-style='statement'] .m-text__body { font-family: var(--serif); font-weight: 300; font-size: var(--t-statement); line-height: 1.04; letter-spacing: -.02em; }
.m-text[data-style='statement'] .m-text__body p { margin-bottom: .5em; }
.m-text[data-style='statement'] em { font-style: italic; }
.m-text[data-style='lead'] .m-text__body { font-size: var(--t-lead); line-height: 1.32; }
.m-text[data-style='body'] .m-text__body { max-width: 62ch; }
.m-text[data-style='body'] .m-text__body p { margin-bottom: 1.15em; }
.m-text[data-style='columns'] .m-text__body { columns: 2; column-gap: var(--gutter); }
.m-text[data-style='columns'] .m-text__body p { break-inside: avoid; }
.m-text[data-style='quote'] .m-text__body { font-family: var(--serif); font-weight: 300; font-style: italic; font-size: clamp(32px, 3.8vw, 68px); line-height: 1.08; letter-spacing: -.015em; text-indent: -.42em; }
.m-text__cite { display: block; margin-top: 32px; font-style: normal; }
.m-text a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .2em; transition: text-underline-offset .25s var(--ease-out), text-decoration-color .25s; }
.m-text a:hover { text-underline-offset: .32em; }
a.label:hover, .label a:hover { text-decoration: underline; text-underline-offset: .25em; }
@media (max-width: 760px) { .m-text[data-style='columns'] .m-text__body { columns: 1; } .m-text__label { margin-bottom: 16px; } }

/* 04 Media ---------------------------------------------------------------- */
.m-media__fig { grid-column: var(--start, 1) / span var(--span, 12); }
.m-media[data-width='full'] .grid { padding-inline: 0; }
.m-media[data-width='full'] .caption { padding-inline: var(--margin); }

/* 05 Gallery -------------------------------------------------------------- */
.m-gallery__items { row-gap: clamp(32px, 4vw, 64px); align-items: end; }
.m-gallery[data-layout='stagger'] .m-gallery__item:nth-child(even) { margin-top: clamp(80px, 14vw, 240px); }
.m-gallery[data-layout='stagger'] .m-gallery__items { align-items: start; }
.m-gallery[data-layout='filmstrip'] .m-gallery__items { display: flex; gap: var(--gutter); overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 16px; scrollbar-width: thin; }
.m-gallery[data-layout='filmstrip'] .m-gallery__item { flex: 0 0 auto; width: clamp(240px, 32vw, 520px); scroll-snap-align: start; }
.m-gallery[data-layout='filmstrip'] .m-gallery__item[data-ratio='9:16'] { width: clamp(180px, 20vw, 320px); }
.m-gallery[data-layout='filmstrip'] .m-gallery__item[data-ratio='2:3'] { width: clamp(210px, 26vw, 420px); }
.m-gallery[data-layout='filmstrip'] .m-gallery__item[data-ratio='16:9'] { width: clamp(300px, 48vw, 760px); }
@media (max-width: 760px) {
  .m-gallery__item { margin-top: 0 !important; } /* phones drop the desktop offsets */
}

/* 06 Split ---------------------------------------------------------------- */
.m-split .grid { align-items: stretch; }
.m-split__media { grid-column: 1 / span var(--media-span, 6); }
.m-split__copy { grid-column: calc(var(--media-span, 6) + 2) / -1; display: flex; flex-direction: column; justify-content: space-between; gap: 48px; }
.m-split[data-side='right'] .m-split__media { grid-column: calc(13 - var(--media-span, 6)) / -1; order: 2; }
.m-split[data-side='right'] .m-split__copy { grid-column: 1 / calc(12 - var(--media-span, 6)); }
.m-split__title { font-family: var(--serif); font-weight: 300; font-size: var(--t-h3); line-height: 1.05; letter-spacing: -.01em; margin-top: 16px; }
.m-split__sub { margin-top: 10px; }
.m-split__body { display: grid; grid-template-columns: repeat(var(--body-cols, 1), minmax(0, 1fr)); gap: var(--gutter); font-size: var(--t-small); line-height: 1.55; max-width: 64ch; }
.m-split__body[data-cols='2'] { --body-cols: 2; }
@media (max-width: 760px) {
  .m-split__media, .m-split[data-side='right'] .m-split__media, .m-split__copy, .m-split[data-side='right'] .m-split__copy { grid-column: 1 / -1; }
  .m-split__media, .m-split[data-side='right'] .m-split__media { order: 0; margin-bottom: 32px; }
  .m-media__fig { margin-top: 0 !important; }
  .m-split__body[data-cols='2'] { --body-cols: 1; }
}

/* 07 Highlights ----------------------------------------------------------- */
.m-highlights[data-style='stats'] .m-highlights__items { row-gap: 48px; }
.hl-stat { grid-column: auto / span 3; padding-top: 18px; position: relative; }
.hl-stat .rule { position: absolute; top: 0; left: 0; right: 0; }
.hl-stat__value { font-family: var(--serif); font-weight: 300; font-size: clamp(56px, 7vw, 128px); line-height: .9; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
@media (max-width: 760px) { .m-highlights__items > .hl-stat:has([data-word]) { grid-column: 1 / -1; } }
.hl-stat__value[data-word] { font-size: clamp(40px, 4.6vw, 84px); letter-spacing: -.025em; }
/* Three highlights share the row in thirds rather than leaving a gap. */
@media (min-width: 761px) { .hl-stat:first-child:nth-last-child(3), .hl-stat:first-child:nth-last-child(3) ~ .hl-stat { grid-column: auto / span 4; } }
.hl-stat__label { margin-top: 18px; }
.hl-stat__body { margin-top: 8px; font-size: var(--t-small); color: var(--muted); max-width: 32ch; }

.m-highlights[data-style='cards'] .m-highlights__items { row-gap: var(--space-s); }
.hl-card { display: block; grid-column: auto / span 4; }
.hl-card[data-size='l'] { grid-column: auto / span 8; }
.hl-card[data-size='m'] { grid-column: auto / span 6; }
.hl-card .frame { transition: transform 1s var(--ease-out); }
.hl-card .frame > .ph, .hl-card .frame > img { transition: filter 1s var(--ease-out); }
.hl-card:hover .frame > .ph, .hl-card:hover .frame > img { filter: saturate(1.25) brightness(1.04); }
.hl-card__meta { display: flex; justify-content: space-between; gap: 16px; padding-top: 14px; }
.hl-card__title { font-family: var(--serif); font-weight: 300; font-size: clamp(24px, 2vw + 6px, 38px); line-height: 1.05; letter-spacing: -.01em; margin-top: 8px; }
.hl-card__title .arrow { display: inline-block; transition: transform .6s var(--ease-out); font-family: var(--sans); font-size: .6em; vertical-align: .2em; margin-left: .3em; }
.hl-card:hover .hl-card__title .arrow { transform: translateX(8px); }
.hl-card__body { margin-top: 10px; font-size: var(--t-small); color: var(--muted); max-width: 44ch; }
.hl-card__num { font-family: var(--sans); }

/* 08 Index ---------------------------------------------------------------- */
.ix { list-style: none; margin: 0; padding: 0; grid-column: 1 / -1; }
.ix__row { position: relative; }
.ix__link {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter);
  align-items: center; padding-block: clamp(16px, 1.8vw, 26px);
  transition: padding .6s var(--ease-out), color .4s;
}
.ix__row .rule { position: absolute; left: 0; right: 0; bottom: 0; }
.ix__row:first-child::before, .ix__row.is-first::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--rule); }
.ix__year { grid-column: 1 / span 1; font-variant-numeric: tabular-nums; }
.ix__title { grid-column: 2 / span 6; font-family: var(--serif); font-weight: 300; font-size: clamp(26px, 2.6vw + 4px, 52px); line-height: 1; letter-spacing: -.015em; }
.ix__client { grid-column: 8 / span 2; }
.ix__role { grid-column: 10 / span 2; }
.ix__go { grid-column: 12 / span 1; text-align: right; opacity: 0; transform: translateX(-12px); transition: opacity .4s, transform .6s var(--ease-out); }
.ix__thumb { display: none; }
.ix:hover a.ix__link { color: var(--muted); }
.ix:hover a.ix__link:hover { color: var(--fg); padding-left: 16px; }
.ix__link:hover .ix__go { opacity: 1; transform: none; }
/* Pager under a long Index list: quiet page numbers, the current one in full colour and underlined. */
.ix__pages { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 24px; margin-top: clamp(24px, 3vw, 40px); }
.ix__nums { display: flex; gap: 18px; }
.ix__num, .ix__step { position: relative; padding: 6px 0; border: 0; background: none; color: var(--muted); cursor: pointer; transition: color .3s; }
.ix__num:hover, .ix__step:not(:disabled):hover, .ix__num[aria-current='page'] { color: var(--fg); }
.ix__num::after { content: ''; position: absolute; left: 0; right: 0; bottom: 2px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform .5s var(--ease-out); }
.ix__num[aria-current='page']::after { transform: scaleX(1); transform-origin: left; }
.ix__step:disabled { opacity: .35; cursor: default; }
@media (max-width: 760px) {
  .ix__link { grid-template-columns: 48px 1fr; row-gap: 6px; align-items: baseline; }
  .ix__year { grid-column: 1; }
  .ix__title { grid-column: 2; }
  .ix__client, .ix__role { grid-column: 2; }
  .ix__role { display: none; }
  .ix__go { display: none; }
  /* The thumbnail takes the number's place; the title and its line sit centred beside it (the 1fr rows above
     and below take whatever height the picture adds). */
  .ix--thumbs .ix__link { grid-template-columns: 56px 1fr; grid-template-rows: 1fr auto auto 1fr; column-gap: 20px; align-items: start; }
  .ix--thumbs .ix__year { display: none; }
  .ix--thumbs .ix__thumb { display: block; aspect-ratio: 2 / 3; grid-column: 1; grid-row: 1 / -1; align-self: center; }
  .ix--thumbs .ix__title { grid-row: 2; }
  .ix--thumbs .ix__client { grid-row: 3; }
}

.cursor-preview {
  position: fixed; left: 0; top: 0; z-index: 40; pointer-events: none;
  width: clamp(180px, 18vw, 300px); aspect-ratio: 2 / 3;
  opacity: 0; transform: translate3d(var(--cx, 0), var(--cy, 0), 0) translate(-50%, -50%) scale(.9);
  transition: opacity .4s var(--ease-out), scale .6s;
  overflow: hidden;
}
.cursor-preview.is-on { opacity: 1; }
.cursor-preview > * { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* At its own proportions: a portrait as tall as the 2:3 frame, a landscape a little wider than it. */
.cursor-preview.is-natural { width: auto; aspect-ratio: auto; }
.cursor-preview.is-natural > img { position: static; display: block; width: auto; height: auto; max-width: clamp(240px, 26vw, 420px); max-height: clamp(270px, 27vw, 450px); }
@media (hover: none) { .cursor-preview { display: none; } }

/* 09 Credits / People ----------------------------------------------------- */
.m-credits__people { row-gap: 40px; align-items: start; }
.person { grid-column: auto / span 2; }
.person .frame { margin-bottom: 10px; }
.person__row { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.person__name { font-size: var(--t-small); font-weight: 400; text-align: right; }
.person__handle { display: block; text-align: right; font-size: var(--t-label); color: var(--muted); }
.m-credits[data-style='list'] .m-credits__people { row-gap: 0; }
.m-credits[data-style='list'] .person { grid-column: auto / span 4; padding-block: 16px; border-top: 1px solid var(--rule); }

/* 10 Wordmark ------------------------------------------------------------- */
.m-wordmark { overflow: hidden; }
.m-wordmark[data-media] { min-height: 100svh; display: flex; flex-direction: column; justify-content: space-between; padding-block: calc(var(--header-h) + 8px) clamp(32px, 4vw, 56px); }
.m-wordmark[data-media][data-position='bottom'] { justify-content: flex-end; }
.m-wordmark[data-media][data-position='bottom'] .wm__cols { order: -1; margin: 0 0 auto; }
.m-wordmark__media { position: absolute; inset: 0; z-index: -1; }
.m-wordmark__media .frame { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
.wm {
  grid-column: 1 / -1; position: relative;
  font-family: var(--serif); font-weight: 300; font-size: var(--wm-size, 18vw);
  line-height: .78; letter-spacing: -.045em; white-space: nowrap;
  padding-top: .06em; /* room for the slices above the cap height */
}
.wm[data-font='sans'] { font-family: var(--sans); font-weight: 500; letter-spacing: -.06em; line-height: .74; }
.wm__word { display: inline-block; }
/* slice: stacked copies, each showing only a thin top band, fold down into the word */
.wm__slices { position: absolute; inset: .06em 0 0; pointer-events: none; }
.wm__slice {
  position: absolute; left: 0; top: 0; white-space: nowrap;
  clip-path: inset(0 0 calc(100% - .3em) 0); /* band reaches the x-height, so lowercase words slice too */
  transform: translate3d(0, calc(var(--k) * -.17em * (1 - var(--wp, 1))), 0);
  opacity: calc(1 - var(--wp, 1) * .999);
}
.wm__cols { margin-top: clamp(24px, 3vw, 48px); row-gap: 24px; }
.wm__col { grid-column: auto / span 3; }
.wm__text { margin-top: 6px; font-size: var(--t-small); line-height: 1.45; color: var(--muted); max-width: 30ch; }
@media (max-width: 760px) { .grid.wm__cols > .wm__col { grid-column: auto / span 3; } }

/* 11 Partners ------------------------------------------------------------- */
.pt__head { align-items: baseline; row-gap: 20px; margin-bottom: var(--space-s); }
.pt__word { font-family: var(--serif); font-weight: 300; font-size: clamp(40px, 5.6vw, 108px); line-height: .9; letter-spacing: -.03em; white-space: nowrap; }
.pt__word--l { grid-column: 1 / span 5; transform: translate3d(calc((1 - var(--pp, 1)) * 22vw), 0, 0); }
.pt__word--r { grid-column: 8 / -1; text-align: right; transform: translate3d(calc((1 - var(--pp, 1)) * -22vw), 0, 0); }
.pt__join { grid-column: 6 / span 2; text-align: center; font-family: var(--sans); font-size: clamp(20px, 2vw, 32px); display: inline-block; transform: rotate(calc((1 - var(--pp, 1)) * 180deg)); }
.pt__intro { grid-column: 5 / span 4; text-align: center; margin-top: 12px; }
.pt__grid { row-gap: var(--gutter); }
.logo {
  grid-column: auto / span 3; aspect-ratio: 2 / 1; display: grid; place-items: center;
  background: color-mix(in srgb, var(--fg) 5%, transparent);
  transition: background .5s var(--ease-out);
}
.pt__grid[data-cols='3'] .logo { grid-column: auto / span 4; }
.pt__grid[data-cols='6'] .logo { grid-column: auto / span 2; }
a.logo:hover { background: color-mix(in srgb, var(--fg) 11%, transparent); }
.logo img { max-width: 58%; max-height: 42%; object-fit: contain; filter: grayscale(1); opacity: .85; }
.logo__name { font-family: var(--serif); font-weight: 300; font-size: clamp(18px, 1.7vw, 28px); letter-spacing: -.01em; color: var(--muted); }
@media (max-width: 760px) {
  .grid.pt__head > .pt__word--l { grid-column: 1 / span 4; }
  .grid.pt__head > .pt__join { grid-column: 5 / span 2; text-align: right; }
  .grid.pt__grid > .logo { grid-column: auto / span 3; }
}

/* 12 Panels --------------------------------------------------------------- */
.m-panels__items { row-gap: var(--gutter); }
.panel { position: relative; display: block; overflow: hidden; color: #F3F1EC; }
/* A panel is as tall as its section's Height, unless its image has a Ratio (.has-ratio), which it keeps. */
.panel:not(.has-ratio) .frame { aspect-ratio: auto; height: 78svh; }
.m-panels[data-height='screen'] .panel:not(.has-ratio) .frame { height: calc(100svh - var(--header-h) * 2); }
.panel .frame::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(20, 14, 14, .32), transparent 34%); pointer-events: none; }
.panel .frame > * { transition: clip-path 1.4s var(--ease-out), scale 1.2s var(--ease-out), filter .8s var(--ease-out); }
.panel__title {
  position: absolute; left: 14px; right: 14px; top: 10px; z-index: 2;
  font-family: var(--serif); font-weight: 300; font-size: clamp(40px, 4.8vw, 92px); line-height: .9; letter-spacing: -.03em;
}
/* The label and number sit below the picture, like a caption, so the picture shows just as it's framed in /god;
   they rise into place as the picture is revealed. */
.panel__bar {
  display: flex; justify-content: space-between; gap: 24px; padding-top: 12px;
  color: var(--fg);
  opacity: 0; transform: translateY(8px); transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
}
.panel__bar > :last-child { flex: none; text-align: right; }
.panel.is-in .panel__bar, .reveal.is-in ~ .panel__bar { opacity: 1; transform: none; }
/* Title size (large is the above): smaller on a laptop or desktop; phones keep theirs. */
@media (min-width: 761px) {
  .m-panels[data-title-size='medium'] .panel__title { font-size: clamp(30px, 3.4vw, 64px); }
  .m-panels[data-title-size='small'] .panel__title { font-size: clamp(22px, 2.4vw, 44px); letter-spacing: -.02em; }
}
.panel:hover .frame > * { scale: 1.04; }
.m-panels__items:hover .panel:not(:hover) .frame > * { filter: saturate(.55) brightness(.8); }
@media (max-width: 760px) { .panel:not(.has-ratio) .frame, .m-panels[data-height='screen'] .panel:not(.has-ratio) .frame { height: 64svh; } }

/* 13–14 Embeds (Spotify, Strava) ------------------------------------------ */
.emb { align-items: center; row-gap: 32px; }
.emb__copy { grid-column: 1 / span 5; }
.emb__frame { grid-column: 7 / -1; }
.emb[data-side='left'] .emb__frame { grid-column: 1 / span 6; }
.emb[data-side='left'] .emb__copy { grid-column: 8 / -1; order: 2; }
.emb[data-copy='0'] .emb__frame { grid-column: 3 / span 8; }
.emb__title { font-family: var(--serif); font-weight: 300; font-size: var(--t-h3); line-height: 1.05; letter-spacing: -.01em; margin-top: 16px; white-space: pre-line; }
.emb__body { margin-top: 20px; font-size: var(--t-small); line-height: 1.55; max-width: 44ch; color: var(--muted); }
.emb__iframe { display: block; width: 100%; border: 0; border-radius: 12px; }
.emb__ph {
  display: flex; flex-direction: column; justify-content: space-between; padding: 18px; border-radius: 12px;
  background: color-mix(in srgb, var(--fg) 7%, transparent); border: 1px dashed color-mix(in srgb, var(--fg) 25%, transparent);
}
.emb__ph-text { font-family: var(--serif); font-weight: 300; font-size: clamp(22px, 2vw, 32px); line-height: 1.1; max-width: 16ch; }
.m-strava .strava-embed-placeholder, .m-strava iframe { max-width: 100%; }
/* Several Strava links: a row of cards to swipe or scroll, the next one peeking in. */
.m-strava__row { display: flex; align-items: flex-start; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory; overscroll-behavior-x: contain; padding-bottom: 12px; scrollbar-width: thin; }
.m-strava__card { flex: 0 0 min(554px, 85%); scroll-snap-align: start; }

/* 15 Taste chart ------------------------------------------------------------- */
.tc { align-items: start; row-gap: 40px; }
.tc__side { grid-column: 1 / span 5; }
.tc__title { font-family: var(--serif); font-weight: 300; font-size: var(--t-h3); line-height: 1.02; letter-spacing: -.015em; margin-top: 16px; }
.tc__intro { margin-top: 18px; font-size: var(--t-small); color: var(--muted); max-width: 44ch; }
.tc__list { list-style: none; margin: clamp(28px, 3vw, 48px) 0 0; padding: 0; counter-reset: tc; }
.tc__row {
  --tc-name: clamp(20px, 1.5vw + 6px, 28px);
  display: grid; grid-template-columns: 34px 1fr auto; column-gap: 12px; align-items: baseline;
  padding: 12px 0; border-top: 1px solid var(--rule); cursor: pointer; transition: padding .5s var(--ease-out), color .3s;
}
.tc__row:last-child { border-bottom: 1px solid var(--rule); }
.tc__row:focus-visible { outline: 1px solid currentColor; outline-offset: 4px; }
.tc__name { font-family: var(--serif); font-weight: 300; font-size: var(--tc-name); line-height: 1.1; }
/* The number and category start on the name's baseline, then rise so their middle meets the middle of its
   capitals: half the difference of the two cap heights (Ghost's is .75em, Lausanne's .72em). */
.tc__num, .tc__cat { translate: 0 calc(.36em - var(--tc-name) * .375); }
.tc__note { grid-column: 2 / -1; margin-top: 4px; font-size: var(--t-small); color: var(--muted); }
.tc__list:hover .tc__row:not(.is-active) { color: var(--muted); }
.tc__row.is-active { padding-left: 10px; }
.tc__map { grid-column: 7 / -1; position: sticky; top: calc(var(--header-h) + 12px); }
.tc__mount { position: relative; aspect-ratio: 4 / 5; max-height: calc(100svh - var(--header-h) - 60px); width: 100%; overflow: hidden; background: var(--map-land, color-mix(in srgb, var(--fg) 6%, transparent)); }
/* Mapbox GL's own stylesheet (loaded after this one) sets its container `position: relative`, which collapsed
   this to no height and the map to nothing; the doubled selector keeps it filling the mount. */
.tc__gl, .tc__gl.mapboxgl-map { position: absolute; inset: 0; width: 100%; height: 100%; }
.tc__credit { margin-top: 10px; color: var(--muted); }
.tc__fallback {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(color-mix(in srgb, var(--fg) 9%, transparent) 1px, transparent 1px),
    linear-gradient(90deg, color-mix(in srgb, var(--fg) 9%, transparent) 1px, transparent 1px);
  background-size: 48px 48px; background-position: center;
}
.tc__fallback .tc__marker { position: absolute; transform: translate(-50%, -50%); }
.tc__marker { border: 0; padding: 0; background: none; cursor: pointer; }
.tc__pin {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: var(--fg); color: var(--bg); font: 400 10px/1 var(--sans); letter-spacing: .02em;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--bg) 70%, transparent);
  opacity: 0; transform: translateY(-18px) scale(.5);
  transition: opacity .5s var(--ease-out), transform .8s var(--ease-out), background .3s;
  transition-delay: calc(var(--i, 0) * 80ms + 200ms), calc(var(--i, 0) * 80ms + 200ms), 0s;
}
.tc__map.is-in .tc__pin { opacity: 1; transform: none; }
.tc__marker.is-active .tc__pin { background: var(--saffron); color: var(--ink); transform: scale(1.25); transition-delay: 0s; }
/* The map's controls in the section's own colours. Mapbox's terms keep its logo as Mapbox draws it; the credit
   they require sits behind their ⓘ button, moved beside the logo, and may change colour and size if it stays
   legible: the button is a disc of the section's background with an i in its text colour, and the credit it opens
   is label type on the same ground, kept clear of the zoom buttons (its width is measured against the map: cqw).
   The zoom buttons are drawn the same way. Mapbox's stylesheet loads after this one, hence the longer selectors. */
.tc__mount { container-type: inline-size; }
/* How far the map is clipped in from each side (phones, until it's held); registered so it can ease. */
@property --tc-inset { syntax: '<length>'; inherits: true; initial-value: 0px; }
/* Mapbox stacks a corner's controls and puts each new one first; here the logo and the ⓘ sit in a row, in that order. */
.tc .tc__map .mapboxgl-ctrl-bottom-left { display: flex; align-items: flex-end; }
.tc .tc__map .mapboxgl-ctrl-bottom-left > .mapboxgl-ctrl { float: none; clear: none; }
.tc .tc__map .mapboxgl-ctrl-bottom-left > .mapboxgl-ctrl-attrib { order: 1; }
.tc .tc__map .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl.mapboxgl-ctrl-attrib.mapboxgl-compact {
  box-sizing: border-box; max-width: calc(100cqw - 108px - 2 * var(--tc-inset)); min-height: 24px; margin: 0 0 6px 8px; padding: 0 0 0 24px; border-radius: 12px;
  background: color-mix(in srgb, var(--bg) 86%, transparent); color: var(--fg);
  /* One line beside the logo: 9px caps, smaller as the map narrows (about 8px on a phone), so the credit never wraps. */
  font: 400 clamp(7px, calc((100cqw - 144px - 2 * var(--tc-inset)) / 26), 9px)/24px var(--sans); letter-spacing: .02em; text-transform: uppercase;
}
.tc .tc__map .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl.mapboxgl-ctrl-attrib.mapboxgl-compact-show { padding: 0 8px 0 28px; }
/* The ⓘ keeps its place when the credit opens: pinned to the box's bottom-left corner, which never moves. */
.tc .tc__map .mapboxgl-ctrl-bottom-left .mapboxgl-ctrl-attrib.mapboxgl-compact .mapboxgl-ctrl-attrib-button {
  left: 0; top: auto; bottom: 0; width: 24px; height: 24px; box-sizing: border-box; border: 1px solid color-mix(in srgb, var(--fg) 45%, transparent);
  border-radius: 50%; background: none; color: var(--fg);
}
.tc .tc__map .mapboxgl-ctrl-attrib-button::before {
  content: ''; position: absolute; inset: 0; background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11.3 10.5h1.4v6h-1.4zM12 7.3a.95.95 0 1 1 0 1.9.95.95 0 0 1 0-1.9z'/%3E%3C/svg%3E") center / 24px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11.3 10.5h1.4v6h-1.4zM12 7.3a.95.95 0 1 1 0 1.9.95.95 0 0 1 0-1.9z'/%3E%3C/svg%3E") center / 24px no-repeat;
}
.tc .tc__map .mapboxgl-ctrl-attrib-button:focus { box-shadow: none; outline: none; }
.tc .tc__map .mapboxgl-ctrl-attrib-button:focus-visible { outline: 1px solid var(--fg); outline-offset: 1px; }
.tc .tc__map .mapboxgl-ctrl-attrib a { color: inherit; opacity: .78; text-decoration: none; white-space: nowrap; }
.tc .tc__map .mapboxgl-ctrl-attrib a:hover { opacity: 1; text-decoration: underline; text-underline-offset: 2px; }
.tc .tc__map .mapboxgl-ctrl-attrib .mapbox-improve-map { font-weight: 400; margin-left: 0; }
.tc .tc__map .mapboxgl-ctrl.mapboxgl-ctrl-group { border-radius: 0; box-shadow: none; background: color-mix(in srgb, var(--bg) 86%, transparent); }
/* The zoom buttons sit on the logo row's insets (6px from the bottom and the side, as the logo is). On a narrow map
   the opened credit needs that line, so they fade out while it's open and come back when it closes. */
.tc .tc__map .mapboxgl-ctrl-bottom-right > .mapboxgl-ctrl.mapboxgl-ctrl-group { margin: 0 6px 6px 0; transition: opacity .3s, visibility .3s; }
@container (max-width: 560px) { .tc .tc__map:has(.mapboxgl-compact-show) .mapboxgl-ctrl.mapboxgl-ctrl-group { opacity: 0; visibility: hidden; } }
.tc .tc__map .mapboxgl-ctrl-group button { width: 32px; height: 32px; color: var(--fg); }
.tc .tc__map .mapboxgl-ctrl-group button + button { border-top: 1px solid color-mix(in srgb, var(--fg) 18%, transparent); }
.tc .tc__map .mapboxgl-ctrl-group button:not(:disabled):hover { background: color-mix(in srgb, var(--fg) 10%, transparent); }
.tc .tc__map .mapboxgl-ctrl-group button:focus-visible { outline: 1px solid var(--fg); outline-offset: -3px; box-shadow: none; }
/* Plus and minus as hairlines in the text colour, in place of Mapbox's grey icons. */
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon,
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon { position: relative; background-image: none; }
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon::before,
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon::after,
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-out .mapboxgl-ctrl-icon::before {
  content: ''; position: absolute; left: 50%; top: 50%; width: 11px; height: 1px; background: currentColor; transform: translate(-50%, -50%);
}
.tc .tc__map .mapboxgl-ctrl button.mapboxgl-ctrl-zoom-in .mapboxgl-ctrl-icon::after { transform: translate(-50%, -50%) rotate(90deg); }
.tc .tc__map .mapboxgl-ctrl-group button:disabled .mapboxgl-ctrl-icon { opacity: .35; }
@media (max-width: 760px) {
  /* One column: the eyebrow, title and intro, then the map, then the places. The side's children join the grid
     so the map can sit between its intro and its list; their top margins space them (grid margins don't
     collapse, so the bottom ones go). */
  .grid.tc { row-gap: 0; }
  .tc__side { display: contents; }
  .tc__side > * { grid-column: 1 / -1; margin-bottom: 0; }
  /* While the places scroll by, the map holds at the top (under the masthead, or at the very top while the masthead
     is tucked away on the way down), so a tapped place shows on it; it lets go with the section, after the last
     place. It stays above the rows passing under it, and is kept to just over half the screen so the list has room. */
  /* Held, it opens out to the screen's edges: the map always spans the full width and is clipped to the column
     (--tc-inset) until it's held (`is-stuck`, set by embeds.js), so the edges ease out without Mapbox resizing;
     its controls ride the same inset. */
  .grid.tc > .tc__map {
    order: 1; position: sticky; top: var(--header-h); z-index: 2; margin: 28px calc(-1 * var(--margin)) 0;
    --tc-inset: var(--margin); clip-path: inset(0 var(--tc-inset));
    transition: top .6s var(--ease-out), --tc-inset .7s var(--ease-out);
  }
  .grid.tc > .tc__map.is-stuck { --tc-inset: 0px; }
  body:has(.masthead.is-hidden) .grid.tc > .tc__map { top: 0; }
  .tc .tc__map .mapboxgl-ctrl-bottom-left { left: var(--tc-inset); }
  .tc .tc__map .mapboxgl-ctrl-bottom-right { right: var(--tc-inset); }
  .tc__list { order: 2; }
  .tc__mount { aspect-ratio: auto; height: min(1.25 * (100vw - 2 * var(--margin)), 55svh); }
  /* A place brought into view from its marker lands below the held map. */
  .tc__row { scroll-margin-top: calc(var(--header-h) + min(1.25 * (100vw - 2 * var(--margin)), 55svh) + 16px); }
}

/* 16–17 Shelves (Books, Films) ------------------------------------------- */
.shelf__grid { row-gap: clamp(40px, 5vw, 72px); align-items: start; }
.shelf__item { display: flex; flex-direction: column; grid-column: auto / span 2; transform: translate3d(0, calc(var(--sp, 0) * var(--dir, 1) * 18px), 0); }
.shelf__row { display: flex; gap: var(--gutter); overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 16px; scrollbar-width: thin; }
.shelf__row .shelf__item { flex: 0 0 clamp(150px, 15vw, 240px); scroll-snap-align: start; }
/* Covers show whole: no parallax overscan. On hover the cover eases in a touch. */
.m-shelf .frame > img, .m-shelf .frame > .ph {
  inset: 0; height: 100%; transform: none;
  transition: clip-path 1.4s var(--ease-out) var(--d, 0ms), scale 1.4s var(--ease-out);
}
@media (hover: hover) { a.shelf__item:hover .frame > * { scale: 1.035; } }
.shelf__meta { display: flex; justify-content: space-between; padding-top: 12px; }
.shelf__title { margin-top: 6px; font-family: var(--serif); font-weight: 300; font-size: clamp(17px, 1vw + 8px, 22px); line-height: 1.15; }
.shelf__by { margin-top: 6px; }
.shelf__note { margin-top: 8px; font-size: var(--t-small); color: var(--muted); }
.shelf__credit { grid-column: 1 / -1; margin-top: 40px; font-size: var(--t-label); }
/* Book covers sit on a plinth: contained, padded, with a soft shadow. Posters fill the frame. */
.m-books .shelf__item .frame > img { object-fit: contain; padding: 11% 15%; filter: drop-shadow(0 10px 14px rgba(0, 0, 0, .22)); }
.shelf__blank-text { position: absolute; inset: 0; z-index: 1; display: flex; flex-direction: column; justify-content: space-between; padding: 14px; color: #F3F1EC; }
.shelf__blank-title { font-family: var(--serif); font-weight: 300; font-size: clamp(18px, 1.4vw + 4px, 26px); line-height: 1.05; }
@media (max-width: 760px) {
  .grid.shelf__grid > .shelf__item { grid-column: auto / span 3; }
  .shelf__item { transform: none; }
}

/* 18 Overlay --------------------------------------------------------------- */
.m-overlay { min-height: 100svh; display: flex; flex-direction: column; justify-content: center; overflow: hidden; }
.ov { align-items: center; }
.ov > * { grid-row: 1; }
.ov__text {
  grid-column: 1 / -1; z-index: 1; margin: 0;
  font-family: var(--serif); font-weight: 300; font-size: clamp(56px, 12vw, 250px); line-height: .96; letter-spacing: -.02em;
}
.ov__text.is-upper { text-transform: uppercase; letter-spacing: .005em; font-size: clamp(48px, 11vw, 230px); }
.ov__line { display: block; white-space: nowrap; transform: translate3d(calc(var(--op, 0) * var(--dir, 1) * 7vw), 0, 0); }
.ov__media { z-index: 2; transform: translate3d(0, calc(var(--op, 0) * -14vh), 0); }
.m-overlay[data-layer='top'] .ov__text { z-index: 3; } /* the text on top of the images */
.ov__media .frame { box-shadow: 0 30px 60px -30px rgba(0, 0, 0, .35); }
.m-overlay[data-shadow='off'] .ov__media .frame { box-shadow: none; }
/* More than one image (data-steps): the section is a stage that holds still (sticky) for a stretch of scrolling per
   image, so each, the first and last included, stays wholly in view while it shows. They stack in one place; each
   later one wipes up over the last (.is-shown, motion.js), and back down on the way up. The first keeps the usual
   reveal. The section is overflow: clip, not hidden, which would stop the stage sticking. */
.ov__stage { display: contents; }
.m-overlay[data-steps] { display: block; min-height: 0; height: calc(100svh + var(--steps) * 75svh); padding-block: 0; overflow: clip; }
.m-overlay[data-steps] .ov__stage { position: sticky; top: 0; height: 100svh; display: flex; flex-direction: column; justify-content: center; }
.m-overlay[data-steps] .ov__media { transform: none; }
.ov__media.is-stack { display: grid; }
.ov__media.is-stack > .frame { grid-area: 1 / 1; }
.ov__media.is-stack > .frame + .frame { clip-path: inset(100% 0 0 0); transition: clip-path 1s var(--ease-out); }
.ov__media.is-stack > .frame.is-shown { clip-path: inset(0); }
/* Transition: fade, each next image fading in over the last (and out again on the way up) instead of wiping up. */
.m-overlay[data-effect='fade'] .ov__media.is-stack > .frame + .frame { clip-path: none; opacity: 0; transition: opacity 1s var(--ease-out); }
.m-overlay[data-effect='fade'] .ov__media.is-stack > .frame.is-shown { opacity: 1; }
.ov__rule { grid-column: 2 / span 1; display: block; width: 1px; height: clamp(60px, 10vw, 140px); margin-top: clamp(32px, 4vw, 64px); background: var(--fg); transform-origin: top; transform: scaleY(0); }
.ov__rule.is-in { transform: scaleY(1); }
@media (max-width: 760px) {
  .ov__line { white-space: normal; }
  .grid.ov > .ov__media { grid-column: 2 / span 4; }
}

/* 19 Immersive --------------------------------------------------------------- */
.m-immersive { padding: 0; }
.m-immersive[data-height='tall'] { height: 180svh; }
.m-immersive[data-height='screen'] { height: 100svh; }
.im__stage { position: sticky; top: 0; height: 100svh; overflow: hidden; display: grid; place-items: center; }
/* Soft top/bottom edges let the page gradient flow into and out of the image. */
.im__bg { position: absolute; inset: 0; -webkit-mask-image: linear-gradient(transparent, #000 10%, #000 90%, transparent); mask-image: linear-gradient(transparent, #000 10%, #000 90%, transparent); }
.im__bg .frame { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
.im__bg .frame > * { --rest: 6px; filter: blur(calc(var(--rest) + (1 - var(--ip, 1)) * 18px)) saturate(1.1); transform: scale(calc(1.06 + (1 - var(--ip, 1)) * .14)); }
.m-immersive[data-blur='none'] .im__bg .frame > * { --rest: 0px; }
.m-immersive[data-blur='heavy'] .im__bg .frame > * { --rest: 18px; }
.im__bg::after {
  content: ''; position: absolute; inset: 0; opacity: .35; mix-blend-mode: overlay; pointer-events: none;
  background-image: var(--grain-svg); background-size: var(--grain-size, 220px);
}
.im__box {
  position: relative; z-index: 1; width: clamp(240px, 30vw, 440px); aspect-ratio: 1; padding: clamp(18px, 2.2vw, 32px);
  display: flex; flex-direction: column; justify-content: space-between; text-align: center;
  background: var(--box-bg); color: var(--box-fg);
  translate: 0 calc((1 - var(--ip, 1)) * 80px);
}
.im__big { margin: 0; font-family: var(--sans); font-weight: 500; font-size: clamp(18px, 2vw, 32px); line-height: 1.02; letter-spacing: -.01em; text-transform: uppercase; }
.im__big .line { display: block; }
.im__mid { margin: 0; font-size: var(--t-small); font-weight: 400; letter-spacing: .02em; }

/* 20 Reveal -------------------------------------------------------------------- */
.m-reveal { min-height: 100svh; padding: 0; overflow: hidden; display: flex; flex-direction: column; justify-content: center; --lens-w: .3; }
.m-reveal[data-lens='s'] { --lens-w: .22; }
.m-reveal[data-lens='l'] { --lens-w: .4; }
.rv__layer { position: absolute; inset: 0; }
.rv__layer .frame { position: absolute; inset: 0; height: 100%; aspect-ratio: auto; }
.rv__soft { -webkit-mask-image: linear-gradient(transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(transparent, #000 8%, #000 92%, transparent); }
.rv__soft .frame > * { filter: blur(26px) saturate(.75) brightness(1.06); transform: scale(1.12); }
.rv__sharp { clip-path: inset(50% 50% 50% 50%); will-change: clip-path; }
.rv__sharp .frame > * { transform: scale(1.12); }
.rv__soft::after, .rv__sharp::after {
  content: ''; position: absolute; inset: 0; opacity: .3; mix-blend-mode: overlay; pointer-events: none;
  background-image: var(--grain-svg); background-size: var(--grain-size, 220px);
}
.rv__copy { position: relative; z-index: 2; pointer-events: none; color: #F3F1EC; align-items: center; }
.rv__copy .label { font-size: clamp(12px, 1.1vw, 16px); letter-spacing: .06em; text-shadow: 0 1px 12px rgba(0, 0, 0, .25); }
.rv__left { grid-column: 2 / span 4; }
.rv__right { grid-column: 8 / span 4; }
.rv__caption {
  position: absolute; left: 0; right: 0; bottom: clamp(48px, 7vw, 96px); z-index: 2; margin: 0; text-align: center; pointer-events: none;
  font-family: var(--serif); font-weight: 300; font-size: clamp(18px, 1.6vw, 28px); letter-spacing: .28em; text-transform: uppercase; color: #F3F1EC;
}
.m-reveal { cursor: crosshair; }
@media (max-width: 760px) {
  .m-reveal { --lens-w: .62; }
  .grid.rv__copy > .rv__left { grid-column: 1 / span 3; }
  .grid.rv__copy > .rv__right { grid-column: 4 / span 3; text-align: right; }
}

/* ==========================================================================
   Templates
   ========================================================================== */

/* Case-study cover ------------------------------------------------------- */
.cs-cover { padding-top: calc(var(--header-h) + clamp(48px, 8vw, 140px)); padding-bottom: var(--space-s); }
.cs-cover__head { align-items: end; row-gap: 32px; }
.cs-cover__eyebrow { grid-column: 1 / span 3; align-self: start; }
.cs-cover__title { grid-column: 4 / -1; font-family: var(--serif); font-weight: 300; font-size: clamp(52px, 8.8vw, 168px); line-height: .9; letter-spacing: -.035em; }
.cs-cover__title sup { font-family: var(--sans); font-size: .16em; letter-spacing: 0; vertical-align: top; position: relative; top: .4em; margin-left: .3em; }
.cs-cover__body { margin-top: var(--space-s); row-gap: 32px; }
.cs-cover__meta { grid-column: 1 / span 6; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px var(--gutter); align-content: start; }
.cs-cover__meta dt { color: var(--muted); }
.cs-cover__meta dd { margin: 4px 0 0; font-size: var(--t-small); font-weight: 400; }
.cs-cover__summary { grid-column: 7 / span 6; font-size: var(--t-lead); line-height: 1.32; }
.cs-cover .rule { grid-column: 1 / -1; margin-top: var(--space-s); }
@media (max-width: 760px) {
  .cs-cover__title { grid-column: 1 / -1; }
  .cs-cover__meta { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Next project ----------------------------------------------------------- */
.next { display: block; padding-block: var(--space-l) var(--space-m); }
.next__label { grid-column: 1 / span 3; }
.next__title { grid-column: 1 / -1; margin-top: 24px; font-family: var(--serif); font-weight: 300; font-size: var(--t-display); line-height: .88; letter-spacing: -.035em; transition: letter-spacing 1s var(--ease-out); }
.next:hover .next__title { letter-spacing: -.015em; }

/* Essay ------------------------------------------------------------------ */
.essay-head { padding-top: calc(var(--header-h) + clamp(64px, 10vw, 180px)); padding-bottom: var(--space-s); }
.essay-head__meta { grid-column: 1 / span 3; display: flex; flex-direction: column; gap: 6px; padding-top: 1em; }
.essay-head__title { grid-column: 4 / span 8; font-family: var(--serif); font-weight: 300; font-size: clamp(44px, 6.4vw, 120px); line-height: .94; letter-spacing: -.03em; }
.essay-head__dek { grid-column: 4 / span 6; margin-top: 32px; font-size: var(--t-lead); line-height: 1.32; color: var(--muted); }
.t-essay .m-text[data-style='body'] .m-text__body { font-size: clamp(17px, .6vw + 12px, 21px); line-height: 1.6; }
.t-essay .m-text[data-style='body'] .m-text__body p:first-child::first-letter {
  font-family: var(--serif); font-weight: 300; float: left; font-size: 4.6em; line-height: .8; padding: .06em .08em 0 0;
}
.t-essay .m-text[data-style='body'] + .m-text[data-style='body'] .m-text__body p:first-child::first-letter { all: unset; }

/* Footer ----------------------------------------------------------------- */
.site-foot { padding-top: var(--space-l); padding-bottom: 72px; }
.site-foot__eyebrow { grid-column: 1 / -1; margin-bottom: 24px; }
/* The clock is a column of its own in the last three grid columns, right-aligned: place and date on the
   labels' line, time and weather beneath, as the links sit under each label. */
.site-foot__now { grid-column: -4 / -1; align-self: start; margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.site-foot__now-line { display: block; white-space: nowrap; }
.site-foot__now-line + .site-foot__now-line { margin-top: 8px; }
.site-foot__now-line > span + span:not([hidden])::before { content: ' · '; }
.site-foot__now-line > span[hidden] { display: none; }
@media (max-width: 760px) {
  .site-foot__now { grid-column: 1 / -1; text-align: left; } /* under the stacked columns, on their left edge; after the rule above so it wins */
}
.site-foot__cta { grid-column: 1 / -1; font-family: var(--serif); font-weight: 300; font-size: var(--t-display); line-height: .86; letter-spacing: -.04em; }
.site-foot__cta a, .site-foot__cta > span[data-preview] { display: inline-block; transition: font-style .3s; }
.site-foot__cta a:hover { font-style: italic; }
.site-foot__cols { margin-top: clamp(64px, 8vw, 140px); row-gap: 32px; }
.site-foot__col { grid-column: auto / span 3; display: flex; flex-direction: column; gap: 6px; font-size: var(--t-small); }
.site-foot__col .label { margin-bottom: 8px; }
.site-foot__col a:hover, .site-foot__col a[aria-current='page'] { text-decoration: underline; text-underline-offset: .2em; }

/* 404 ---------------------------------------------------------- */
.state { min-height: 100svh; display: grid; place-items: center; text-align: center; padding: var(--margin); }
.state h1 { font-family: var(--serif); font-weight: 300; font-size: var(--t-display); line-height: .9; letter-spacing: -.035em; }
/* The 404 page carries a game, so its headline steps down a size and clears the header. */
.state:has(.frog) { padding: calc(var(--header-h) + var(--margin)) var(--margin) var(--space-s); }
.state:has(.frog) h1 { font-size: clamp(44px, 7.2vw, 128px); }
.state__somewhere { text-decoration: underline; text-decoration-thickness: .03em; text-underline-offset: .1em; transition: opacity .3s; }
.state__somewhere:hover { opacity: .6; }
.state__sub { margin: 24px auto 0; max-width: 34ch; font-size: var(--t-body); }
/* 404 Frogger */
.frog { width: min(720px, 100%); margin: 40px auto 0; }
.frog__stage { position: relative; width: fit-content; margin: 0 auto; touch-action: none; cursor: pointer; }
.frog__board { display: block; border-radius: 6px; outline: 1px solid var(--rule); outline-offset: 0; }
.frog__splat { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 38%; border-radius: 6px; opacity: 0; transform: scale(1.04); transition: opacity .25s, transform .6s var(--ease-out); pointer-events: none; }
.frog__splat.is-on { opacity: 1; transform: none; }
.frog__note { position: absolute; left: 50%; bottom: 50%; transform: translate(-50%, 50%); padding: 7px 12px; border-radius: 999px; background: var(--fg); color: var(--bg); white-space: nowrap; pointer-events: none; transition: opacity .5s ease; }
.frog__note.is-off { opacity: 0; }
.frog__splat.is-on ~ .frog__note { bottom: 16px; transform: translateX(-50%); }
.frog__board:focus-visible { outline: 1px solid var(--fg); }
.frog__bar { display: flex; justify-content: space-between; align-items: center; gap: 16px; width: fit-content; min-width: min(100%, 320px); margin: 12px auto 0; color: var(--muted); font-variant-numeric: tabular-nums; }
.frog__full { padding: 14px 0; margin: -14px 0; border: 0; background: none; color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; }
.frog__full:hover { color: var(--fg); }
/* Full screen (native, or the fallback overlay where the browser has no fullscreen API) */
.frog.is-full { position: fixed; inset: 0; z-index: 1000; width: auto; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 16px; background: var(--bg); }
.frog.is-full .frog__bar { width: auto; min-width: 0; }
.frog-full { overflow: hidden; }

/* Mobile: everything on the grid stacks to full width, except the few
   modules that deliberately pair items two-up. ----------------------------- */
@media (max-width: 760px) {
  .grid > :not(.keep) { grid-column: 1 / -1; }
  .m-gallery__items > .m-gallery__item:not([data-ratio='16:9']),
  .m-highlights__items > .hl-stat,
  .m-credits__people > .person { grid-column: auto / span 3; }
  .m-gallery__items > .m-gallery__item:only-child { grid-column: 1 / -1; }
  .m-credits[data-style='list'] .m-credits__people > .person { grid-column: 1 / -1; }
  .cs-cover__summary { order: -1; }
  .m-chapter__num { font-size: 52vw; opacity: .5; }
}

/* Reduced motion ---------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; transition-delay: 0ms !important; animation: none !important; }
  .split .w > span, .fade, .reveal > * { opacity: 1 !important; clip-path: none !important; }
  .split .w > span, .fade { transform: none !important; }
  .scrub .sw { opacity: 1 !important; }
  .frame > img, .frame > video, .frame > .ph { transform: none !important; }
}

/* Admin live preview: edits re-render instantly instead of replaying entrance animations. */
.is-instant .split .w > span, .is-instant .fade, .is-instant .reveal > *, .is-instant .rule, .is-instant mark { transition: none !important; }

/* Contact form ------------------------------------------------------------ */
/* Header like a chapter in miniature; the introduction sits in the first three columns and the form
   starts on column 4, where text modules start. Fields are large and light, ruled underneath. */
.m-contact__head { margin-bottom: clamp(40px, 5vw, 88px); align-items: start; }
.m-contact__eyebrow { grid-column: 1 / span 3; padding-top: .9em; }
.m-contact__title { grid-column: 4 / span 9; font-family: var(--serif); font-weight: 300; font-size: var(--t-statement); line-height: 1; letter-spacing: -.02em; }
.m-contact__body { align-items: start; }
.m-contact__aside { grid-column: 1 / span 3; display: grid; gap: 20px; position: sticky; top: calc(var(--header-h) + 24px); }
.m-contact__intro { margin: 0; max-width: 30ch; }
.m-contact__note { margin: 0; max-width: 32ch; }
.m-contact__form { grid-column: 4 / span 9; position: relative; --error: color-mix(in srgb, #C4513C 75%, var(--fg)); }
.m-contact__fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(32px, 3.4vw, 52px) var(--gutter); }
.m-contact__field { position: relative; display: grid; align-content: start; gap: 12px; }
.m-contact__field.is-wide { grid-column: 1 / -1; }
/* The rule under each field draws in from the left on focus (a 1px background line over the border). */
.m-contact__input { width: 100%; padding: 4px 0 14px; border: 0; border-bottom: 1px solid var(--rule); border-radius: 0; background: linear-gradient(currentColor, currentColor) left bottom / 0 1px no-repeat border-box; color: inherit; font: inherit; font-weight: 300; font-size: var(--t-lead); line-height: 1.25; letter-spacing: -.005em; transition: background-size .8s var(--ease-out), border-color .3s; }
.m-contact__input::placeholder { color: var(--muted); opacity: .5; }
.m-contact__input:focus { outline: none; background-size: 100% 1px; }
/* Autofill: browsers force a pale fill and black text. Clip that fill to the letters, which are then
   drawn in the form's own colour over it. */
.m-contact__input:-webkit-autofill { -webkit-text-fill-color: var(--fg); caret-color: var(--fg); -webkit-background-clip: text; background-clip: text; }
.m-contact__label { display: flex; justify-content: space-between; gap: 12px; }
.m-contact__count { font-variant-numeric: tabular-nums; transition: color .3s; }
.m-contact__count.is-near { color: var(--error); }
.m-contact__error { color: var(--error); font-size: var(--t-small); font-weight: 400; line-height: 1.4; }
.m-contact__error:empty { display: none; }
.m-contact__field.is-error .m-contact__input { border-bottom-color: var(--error); background-image: linear-gradient(var(--error), var(--error)); background-size: 100% 1px; }
.m-contact__field.is-error .m-contact__label > span:first-child { color: var(--error); }
textarea.m-contact__input { display: block; min-height: 5.6em; line-height: 1.35; resize: vertical; }
@supports (field-sizing: content) { textarea.m-contact__input { field-sizing: content; min-height: 4.2em; max-height: 60vh; resize: none; } }
.m-contact__trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.m-contact__check { margin-top: clamp(36px, 3.6vw, 56px); }
.m-contact__human { display: flex; align-items: center; gap: 14px; padding: 11px 0; margin: -11px 0; font-size: var(--t-small); cursor: pointer; }
.m-contact__human input { appearance: none; flex: none; display: grid; place-content: center; width: 22px; height: 22px; margin: 0; border: 1px solid currentColor; border-radius: 5px; background: transparent; color: inherit; cursor: inherit; transition: background .3s; }
.m-contact__human input::after { content: ''; width: 10px; height: 5px; border: solid var(--bg); border-width: 0 0 1.5px 1.5px; transform: translateY(-1px) rotate(-45deg) scale(0); transition: transform .35s var(--ease-out); }
.m-contact__human input:checked { background: var(--fg); }
.m-contact__human input:checked::after { transform: translateY(-1px) rotate(-45deg) scale(1); }
.m-contact__human input:focus-visible { outline: 1px solid currentColor; outline-offset: 3px; }
.m-contact__form.is-verified .m-contact__human { cursor: default; }
.m-contact__game { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows .7s var(--ease-out), opacity .4s; }
.m-contact__game.is-open { grid-template-rows: 1fr; opacity: 1; }
.m-contact__game-inner { min-height: 0; overflow: hidden; }
.m-contact__hint { margin: 22px 0 14px; }
.m-contact__board .frog { width: 100%; margin: 0; }
.m-contact__board .frog__stage { margin: 0; }
.m-contact__board .frog__bar { margin: 12px 0 0; }
.m-contact__foot { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 28px; margin-top: clamp(28px, 3vw, 44px); }
.m-contact__send { display: inline-flex; align-items: center; gap: 16px; height: 56px; padding: 0 28px 0 32px; border: 1px solid currentColor; border-radius: 999px; background: none; color: inherit; font: inherit; cursor: pointer; transition: background .4s, color .4s, opacity .4s; }
.m-contact__arrow { display: inline-block; font-size: 18px; line-height: 1; transition: transform .6s var(--ease-out); }
.m-contact__send:not(:disabled):hover { background: var(--fg); color: var(--bg); }
.m-contact__send:not(:disabled):hover .m-contact__arrow { transform: translateX(6px); }
.m-contact__send:disabled { opacity: .3; cursor: default; }
.m-contact__status { margin: 0; color: var(--muted); }
.m-contact__status.is-error { color: var(--error); }
.m-contact__form.is-sent > :not(.m-contact__thanks) { display: none; }
.m-contact__thanks { display: grid; gap: 18px; }
.m-contact__thanks[hidden] { display: none; }
.m-contact__thanks-text { margin: 0; font-family: var(--serif); font-weight: 300; font-size: var(--t-h3); line-height: 1.08; letter-spacing: -.01em; max-width: 20ch; }
@media (max-width: 760px) {
  .m-contact__eyebrow { padding-top: 0; margin-bottom: 16px; }
  .m-contact__aside { position: static; margin-bottom: 44px; }
  .m-contact__fields { grid-template-columns: 1fr; }
}
