:root {
  --ink: #15161b;
  --signal: #fe3b03;
  /* Same hue as --signal, darkened past WCAG AA on ivory (4.81:1) rather than
     landing exactly on 4.50, so rounding cannot push it under. Use for small
     text on light backgrounds; --signal stays for dark backgrounds and large
     display type. */
  --signal-ink: #c62d01;
  --ivory: #f3eee3;
  --paper: #faf7f0;
  --line-light: rgba(243, 238, 227, 0.17);
  --line-dark: rgba(21, 22, 27, 0.16);
  --side: clamp(22px, 4.5vw, 76px);
  --header: 68px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  color-scheme: dark;
  font-family:
    -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue",
    Arial, sans-serif;
  font-synthesis: none;
  text-rendering: geometricPrecision;
}

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

html {
  scroll-behavior: smooth;
  /* Without this the fixed topbar covers whatever sits at the top of a jump
     target — the #worlds ticker was rendering completely behind it, and behind
     a backdrop-filter at that (WCAG 2.4.11 Focus Not Obscured). */
  scroll-padding-top: calc(var(--header) + 14px);
  background: var(--ink);
}

body {
  margin: 0;
  min-width: 320px;
  overflow-x: clip;
  background: var(--ink);
  color: var(--ivory);
  cursor: default;
  -webkit-font-smoothing: antialiased;
}

body.is-loading {
  cursor: wait;
}

/* The custom .cursor-signal is hidden below 980px and on coarse pointers, so
   interactive elements keep a real pointer cursor as the fallback affordance. */
a,
button {
  cursor: pointer;
}

img {
  display: block;
  max-width: 100%;
  /* Required: the width/height attributes on .field__mark act as a
     presentational hint (height: 2048px), which would stretch the square mark
     into a vertical band once CSS sets only its width. */
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
}

h1,
h2,
h3,
p {
  margin: 0;
}

::selection {
  background: var(--signal);
  color: var(--ink);
}

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

.skip-link {
  position: fixed;
  z-index: 1000;
  top: 12px;
  left: 12px;
  transform: translateY(-160%);
  padding: 11px 15px;
  border-radius: 99px;
  background: var(--ivory);
  color: var(--ink);
  font-size: 13px;
  font-weight: 700;
  transition: transform 180ms ease;
}

.skip-link:focus {
  transform: none;
}

.progress {
  position: fixed;
  z-index: 140;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  pointer-events: none;
}

.progress i {
  display: block;
  width: 100%;
  height: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--signal);
  will-change: transform;
}

.cursor-signal {
  position: fixed;
  z-index: 150;
  top: 0;
  left: 0;
  width: 12px;
  height: 12px;
  transform: translate(-50%, -50%) rotate(45deg);
  border: 1px solid var(--signal);
  pointer-events: none;
  transition:
    width 240ms var(--ease),
    height 240ms var(--ease),
    background 240ms ease;
  will-change: transform;
}

body:has(a:hover, button:hover) .cursor-signal {
  width: 34px;
  height: 34px;
  background: rgba(254, 59, 3, 0.16);
}

.topbar {
  position: fixed;
  z-index: 120;
  top: 0;
  left: 0;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  height: var(--header);
  padding: 0 var(--side);
  border-bottom: 1px solid var(--line-light);
  background: rgba(21, 22, 27, 0.74);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  transition:
    color 300ms ease,
    background 300ms ease,
    border-color 300ms ease;
}

/* Driven by body.is-light (not .topbar.is-light) so every fixed overlay can
   react to the light sections from CSS alone. */
body.is-light .topbar {
  border-color: var(--line-dark);
  background: rgba(243, 238, 227, 0.82);
  color: var(--ink);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  gap: 10px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.025em;
}

.wordmark__mark {
  width: 9px;
  height: 9px;
  transform: rotate(45deg);
  background: var(--signal);
}

.topbar__nav {
  display: flex;
  gap: 28px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.topbar__nav a {
  position: relative;
  opacity: 0.68;
  transition: opacity 220ms ease;
}

.topbar__nav a::after {
  position: absolute;
  right: 0;
  bottom: -7px;
  left: 0;
  height: 1px;
  transform: scaleX(0);
  transform-origin: right;
  background: currentColor;
  content: "";
  transition: transform 280ms var(--ease);
}

.topbar__nav a:hover,
.topbar__nav a:focus-visible {
  opacity: 1;
}

.topbar__nav a:hover::after,
.topbar__nav a:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

.topbar__meta {
  justify-self: end;
  font: 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
  opacity: 0.58;
}

/* At 0.58 the ink text composited to 4.21:1 over the light bar and 3.93:1 over
   the contact section — under AA for 10px type. */
body.is-light .topbar__meta {
  opacity: 0.78;
}

/* Shown inside the mobile overlay only; the desktop bar uses .topbar__meta. */
.topbar__nav-meta {
  display: none;
}

.nav-toggle {
  display: none;
  align-items: center;
  justify-self: end;
  gap: 9px;
  padding: 9px 0 9px 12px;
  border: 0;
  background: none;
  color: inherit;
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.nav-toggle__mark {
  position: relative;
  width: 11px;
  height: 11px;
  transform: rotate(45deg);
  border: 1px solid var(--signal);
  transition:
    background 240ms ease,
    transform 320ms var(--ease);
}

body.nav-open .nav-toggle__mark {
  transform: rotate(135deg);
  background: var(--signal);
}

.nav-toggle:focus-visible {
  outline: 1px solid var(--signal);
  outline-offset: 4px;
}

.section-index {
  position: fixed;
  z-index: 110;
  top: 50%;
  right: 18px;
  display: grid;
  justify-items: center;
  gap: 10px;
  transform: translateY(-50%);
  font: 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  pointer-events: none;
}

.section-index i {
  display: block;
  width: 1px;
  height: 90px;
  background: linear-gradient(var(--signal) 0 var(--section-progress, 0%), var(--line-light) var(--section-progress, 0%));
}

/* Over the ivory and signal sections the default ivory counter rendered at
   1.0:1 — invisible. */
body.is-light .section-index {
  color: var(--ink);
}

body.is-light .section-index i {
  background: linear-gradient(
    var(--ink) 0 var(--section-progress, 0%),
    var(--line-dark) var(--section-progress, 0%)
  );
}

.eyebrow {
  font: 700 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.scene {
  position: relative;
}

.field {
  height: 420vh;
  min-height: 2600px;
  background: var(--ink);
}

.field__sticky {
  position: sticky;
  top: 0;
  width: 100%;
  /* No min-height: a floor taller than the viewport makes this pinned,
     overflow-hidden box extend past the screen, permanently clipping whatever
     sits at its bottom edge on short viewports (landscape phones). */
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--ink);
}

.field__grid {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  inset: 0;
  opacity: 0.65;
  background-image:
    linear-gradient(var(--line-light) 1px, transparent 1px),
    linear-gradient(90deg, var(--line-light) 1px, transparent 1px);
  background-size: 8.333vw 8.333vw;
  /* The -webkit- twin is what keeps the baseline at Chrome 87 instead of 120;
     without it the hero grid runs at full strength into the readout line. */
  -webkit-mask-image: linear-gradient(to bottom, black, transparent 88%);
  mask-image: linear-gradient(to bottom, black, transparent 88%);
}

.field__cross {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  background: var(--line-light);
}

.field__cross--x {
  width: 100%;
  height: 1px;
  transform: translate(-50%, -50%);
}

.field__cross--y {
  width: 1px;
  height: 100%;
  transform: translate(-50%, -50%);
}

/* The <picture> wrapper must not take part in layout — the mark inside it is
   absolutely positioned against .field__sticky. */
.field__sticky picture {
  display: contents;
}

.field__mark {
  /* --mark-x and --mark-opacity are owned by the breakpoints below. script.js
     only writes the 0..1 progress variables (--mark-travel, --mark-visibility,
     --mark-scale, --mark-rotate, --mark-gray, --mark-bright), so a media query
     can still reposition and dim the mark per viewport. */
  --mark-x: 70%;
  --mark-shift: 20%;
  --mark-opacity: 0.9;
  position: absolute;
  z-index: 2;
  top: 50%;
  left: calc(var(--mark-x) - var(--mark-shift) * var(--mark-travel, 0));
  width: min(59vw, 880px);
  max-width: none;
  opacity: calc(var(--mark-opacity) * var(--mark-visibility, 1));
  transform: translate(-50%, -50%) scale(var(--mark-scale, 1.24))
    rotate(var(--mark-rotate, -8deg));
  filter: grayscale(var(--mark-gray, 1)) brightness(var(--mark-bright, 2.3));
  mix-blend-mode: screen;
  will-change: transform, opacity, filter;
}

.field__coordinates {
  position: absolute;
  z-index: 3;
  top: calc(var(--header) + 24px);
  right: var(--side);
  display: flex;
  gap: 24px;
  font: 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
  opacity: 0.58;
}

.field__copy {
  position: absolute;
  z-index: 5;
  top: 50%;
  left: var(--side);
  width: min(54vw, 850px);
  opacity: var(--copy-opacity, 1);
  transform: translateY(calc(-50% - var(--copy-lift, 0px)));
}

.field__copy .eyebrow {
  margin-bottom: clamp(24px, 4vh, 44px);
  color: var(--signal);
}

.phase-word {
  position: relative;
  height: clamp(50px, 11vw, 170px);
  overflow: hidden;
}

.phase-word span {
  position: absolute;
  top: 0;
  left: 0;
  inset: 0 auto auto 0;
  transform: translateY(116%);
  font-size: clamp(46px, 11vw, 174px);
  font-weight: 800;
  letter-spacing: -0.075em;
  line-height: 0.92;
  opacity: 0;
  transition:
    transform 640ms var(--ease),
    opacity 300ms ease;
}

.phase-word span.is-active {
  transform: none;
  opacity: 1;
}

.field h1 {
  margin-top: 12px;
  font-size: clamp(46px, 10.4vw, 165px);
  font-weight: 800;
  letter-spacing: -0.075em;
  line-height: 0.82;
}

.field h1 span {
  display: block;
}

/* Only the closing word carries the signal colour; the first span is the
   visually hidden full sentence. */
.field h1 span:last-child {
  color: var(--signal);
}

.field__readout {
  position: absolute;
  z-index: 6;
  right: var(--side);
  bottom: 36px;
  left: var(--side);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 18px;
  font: 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
}

.field__readout i {
  height: 1px;
  background: var(--line-light);
}

.field__scan {
  position: absolute;
  z-index: 4;
  top: var(--header);
  bottom: 0;
  left: -3px;
  width: 3px;
  transform: translateX(0);
  background: var(--signal);
  box-shadow: 0 0 46px rgba(254, 59, 3, 0.58);
  will-change: transform;
}

.field__exit {
  position: absolute;
  z-index: 8;
  right: 0;
  bottom: 0;
  left: 0;
  height: 100%;
  transform: translateY(101%);
  background: var(--ivory);
  /* No will-change: this is a full-viewport layer that only moves during the
     last ~11% of the section, and the browser promotes an actively transformed
     element on its own. A permanent hint just holds the memory. */
}

.thesis {
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(280px, 0.55fr);
  gap: clamp(60px, 9vw, 150px);
  min-height: 100vh;
  min-height: 100svh;
  padding: 160px var(--side) 120px;
  background: var(--ivory);
  color: var(--ink);
}

.thesis__lead .eyebrow {
  margin-bottom: 38px;
  color: var(--signal-ink);
}

.thesis h2 {
  max-width: 920px;
  font-size: clamp(56px, 7.8vw, 122px);
  font-weight: 800;
  letter-spacing: -0.065em;
  line-height: 0.93;
}

.thesis h2 em {
  display: block;
  color: var(--signal);
  font-style: normal;
}

.thesis__body {
  display: grid;
  align-content: end;
  gap: 34px;
  padding-bottom: 84px;
}

.thesis__body p {
  font-size: clamp(16px, 1.25vw, 21px);
  letter-spacing: -0.02em;
  line-height: 1.5;
}

.thesis__body p + p {
  padding-top: 34px;
  border-top: 1px solid var(--line-dark);
}

.thesis__signature {
  position: absolute;
  right: var(--side);
  bottom: 40px;
  left: var(--side);
  display: flex;
  align-items: center;
  gap: 16px;
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.12em;
}

.thesis__signature i {
  flex: 1;
  height: 1px;
  background: var(--line-dark);
}

.method {
  height: 420vh;
  min-height: 2800px;
  background: var(--ink);
}

.method__sticky {
  position: sticky;
  top: 0;
  display: grid;
  grid-template-columns: minmax(300px, 0.72fr) minmax(520px, 1.28fr);
  gap: 6vw;
  width: 100%;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  padding: calc(var(--header) + 58px) var(--side) 46px;
}

/* Under ~640px of viewport height the four stacked cards cannot fit in one
   pinned screen, so the section falls back to the same static layout the phone
   breakpoint uses instead of clipping the card copy. */
@media (max-height: 640px) and (min-width: 681px) {
  .method,
  .method__sticky {
    position: relative;
    display: block;
    height: auto;
    min-height: 0;
    overflow: visible;
  }

  .method__intro {
    margin-bottom: 60px;
  }

  .method__stack {
    display: grid;
    gap: 14px;
    height: auto;
  }

  .method-card {
    position: relative;
    min-height: 420px;
    transform: none !important;
    opacity: 1 !important;
  }

  .method__meter {
    display: none;
  }
}

.method__intro {
  align-self: center;
}

.method__intro .eyebrow {
  margin-bottom: 28px;
  color: var(--signal);
}

.method__intro h2 {
  font-size: clamp(48px, 5.4vw, 86px);
  font-weight: 800;
  letter-spacing: -0.055em;
  line-height: 0.94;
}

.method__intro > p {
  max-width: 470px;
  margin-top: 34px;
  font-size: clamp(15px, 1.15vw, 19px);
  line-height: 1.52;
  opacity: 0.62;
}

.method__meter {
  width: min(370px, 100%);
  height: 2px;
  margin-top: 54px;
  background: var(--line-light);
}

.method__meter i {
  display: block;
  width: 100%;
  height: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--signal);
  will-change: transform;
}

.method__stack {
  position: relative;
  align-self: center;
  height: min(66vh, 610px);
}

.method-card {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  inset: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 18px 32px;
  padding: clamp(28px, 4vw, 58px);
  border: 1px solid rgba(21, 22, 27, 0.14);
  background: var(--ivory);
  color: var(--ink);
  transform-origin: bottom center;
  box-shadow: 0 38px 110px rgba(0, 0, 0, 0.26);
}

/* Only promote to a GPU layer where the cards actually animate — below 681px
   they are pinned with transform: none. */
@media (min-width: 681px) {
  .method-card {
    will-change: transform, opacity;
  }
}

/* Keyed to the --01..--04 classes already in the markup rather than :nth-child,
   so the numbers cannot silently drift from the colours if the DOM order
   changes. */
.method-card--02 {
  background: var(--paper);
}

.method-card--03 {
  background: var(--signal);
}

.method-card--04 {
  background: var(--ink);
  color: var(--ivory);
  outline: 1px solid var(--line-light);
}

.method-card > span {
  font: 800 clamp(42px, 6vw, 92px) / 0.8 ui-monospace, SFMono-Regular,
    Menlo, monospace;
  color: var(--signal);
}

.method-card--03 > span {
  color: var(--ink);
}

.method-card > p {
  justify-self: end;
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.12em;
}

.method-card h3 {
  grid-column: 1 / -1;
  align-self: center;
  font-size: clamp(44px, 6.3vw, 102px);
  font-weight: 800;
  letter-spacing: -0.065em;
  line-height: 0.88;
}

.method-card small {
  grid-column: 2;
  max-width: 410px;
  justify-self: end;
  font-size: clamp(14px, 1.05vw, 18px);
  line-height: 1.45;
}

.world-index {
  padding: 0 var(--side) 140px;
  overflow: hidden;
  background: var(--ivory);
  color: var(--ink);
}

.ticker {
  width: calc(100% + var(--side) * 2);
  margin-left: calc(var(--side) * -1);
  overflow: hidden;
  border-top: 1px solid var(--line-dark);
  border-bottom: 1px solid var(--line-dark);
  background: var(--signal);
}

.ticker div {
  width: max-content;
  padding: 17px 0;
  animation: ticker 22s linear infinite;
  font: 800 11px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

@keyframes ticker {
  to {
    transform: translateX(-50%);
  }
}

.world-index__header {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 60px;
  padding: 120px 0 76px;
}

.world-index__header .eyebrow {
  align-self: start;
  color: var(--signal-ink);
}

.world-index__header h2 {
  max-width: 850px;
  font-size: clamp(52px, 6.7vw, 106px);
  font-weight: 800;
  letter-spacing: -0.06em;
  line-height: 0.94;
}

.world-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.world-card {
  min-height: 560px;
  padding: 20px;
  border: 1px solid var(--line-dark);
}

.world-card--dark {
  background: var(--ink);
  color: var(--ivory);
}

.world-card--signal {
  background: var(--signal);
  color: var(--ink);
}

.world-card--paper {
  background: var(--paper);
  /* --paper vs --ivory is only 1.08:1, so the edge carries the separation. */
  border-color: rgba(21, 22, 27, 0.34);
}

.world-card > span {
  font: 700 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.1em;
}

.world-card__visual {
  position: relative;
  height: 310px;
  margin: 32px 0 40px;
  overflow: hidden;
  border: 1px solid currentColor;
}

.world-card__visual--systems {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  align-items: end;
  padding: 28px;
}

.world-card__visual--systems i {
  display: block;
  height: var(--h);
  background: var(--ivory);
}

.world-card__visual--systems i:nth-child(1) {
  --h: 35%;
}

.world-card__visual--systems i:nth-child(2) {
  --h: 58%;
}

.world-card__visual--systems i:nth-child(3) {
  --h: 78%;
}

.world-card__visual--systems i:nth-child(4) {
  --h: 100%;
  background: var(--signal);
}

.world-card__visual--narrative i {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  width: 62%;
  height: 62%;
  transform: translate(-50%, -50%) rotate(45deg) scale(var(--s));
  border: 2px solid var(--ink);
}

.world-card__visual--narrative i:nth-child(1) {
  --s: 1;
}

.world-card__visual--narrative i:nth-child(2) {
  --s: 0.66;
}

.world-card__visual--narrative i:nth-child(3) {
  --s: 0.3;
  background: var(--ink);
}

.world-card__visual--social {
  display: grid;
  place-items: center;
}

.world-card__visual--social i {
  position: absolute;
  width: 13px;
  height: 13px;
  /* Offsets are folded into transform rather than using the standalone
     translate property: where that is unsupported all five diamonds stack on
     top of each other in the middle of the card. */
  transform: rotate(45deg);
  background: var(--ink);
}

.world-card__visual--social i:nth-child(1) {
  transform: translate(-90px, -60px) rotate(45deg);
}

.world-card__visual--social i:nth-child(2) {
  transform: translate(90px, -60px) rotate(45deg);
}

.world-card__visual--social i:nth-child(3) {
  transform: rotate(45deg);
  width: 28px;
  height: 28px;
  background: var(--signal);
}

.world-card__visual--social i:nth-child(4) {
  transform: translate(-90px, 60px) rotate(45deg);
}

.world-card__visual--social i:nth-child(5) {
  transform: translate(90px, 60px) rotate(45deg);
}

.world-card h3 {
  font-size: clamp(32px, 3.4vw, 54px);
  font-weight: 800;
  letter-spacing: -0.045em;
}

.world-card p {
  max-width: 390px;
  margin-top: 14px;
  font-size: 15px;
  line-height: 1.5;
  opacity: 0.68;
}

/* Ink at 68% over signal composites to ~3.3:1; at full strength it is 5.02:1.
   The other two cards clear AA with the shared opacity. */
.world-card--signal p {
  opacity: 1;
}

.principles {
  display: grid;
  grid-template-columns: minmax(320px, 0.86fr) minmax(0, 1.14fr);
  min-height: 100vh;
  min-height: 100svh;
  background: var(--ink);
}

.principles__visual {
  position: relative;
  min-height: 720px;
  overflow: hidden;
  border-right: 1px solid var(--line-light);
}

.principles__visual::before,
.principles__visual::after {
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--line-light);
  content: "";
}

.principles__visual::before {
  width: 100%;
  height: 1px;
  transform: translate(-50%, -50%);
}

.principles__visual::after {
  width: 1px;
  height: 100%;
  transform: translate(-50%, -50%);
}

.principles__visual {
  /* Single source for every diamond offset. Viewport-relative so the cluster
     cannot land outside its own box on short or narrow screens — the old fixed
     150px/210px values did exactly that. */
  /* vmin equals vh in landscape, where the box is only 52svh tall — an
     unclamped 27vmin threw two of the four diamonds outside it. */
  --d: clamp(58px, min(20vmin, 16vh), 150px);
  --d-far: clamp(74px, min(27vmin, 21vh), 210px);
}

.principles__visual i,
.principles__visual span {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: var(--ivory);
  transition: transform 650ms var(--ease);
}

.principles__visual i:nth-child(1) {
  transform: translate(calc(-50% - var(--d)), calc(-50% - var(--d)))
    rotate(45deg);
}

.principles__visual i:nth-child(2) {
  transform: translate(calc(-50% + var(--d)), calc(-50% - var(--d)))
    rotate(45deg);
}

.principles__visual i:nth-child(3) {
  transform: translate(calc(-50% + var(--d)), calc(-50% + var(--d)))
    rotate(45deg);
}

.principles__visual i:nth-child(4) {
  transform: translate(calc(-50% - var(--d)), calc(-50% + var(--d)))
    rotate(45deg);
}

.principles__visual span {
  width: 42px;
  height: 42px;
  background: var(--signal);
}

.principles[data-active="agency"] .principles__visual i:nth-child(1),
.principles[data-active="agency"] .principles__visual i:nth-child(3) {
  transform: translate(calc(-50% - var(--d) * 0.5), calc(-50% - var(--d) * 0.5))
    rotate(135deg);
}

.principles[data-active="agency"] .principles__visual i:nth-child(2),
.principles[data-active="agency"] .principles__visual i:nth-child(4) {
  transform: translate(calc(-50% + var(--d) * 0.5), calc(-50% + var(--d) * 0.5))
    rotate(135deg);
}

.principles[data-active="craft"] .principles__visual i {
  width: var(--d);
  height: 2px;
  transform: translate(-50%, -50%) rotate(var(--r));
  background: var(--ivory);
}

.principles[data-active="craft"] .principles__visual i:nth-child(1) {
  --r: 0deg;
}

.principles[data-active="craft"] .principles__visual i:nth-child(2) {
  --r: 90deg;
}

.principles[data-active="craft"] .principles__visual i:nth-child(3) {
  --r: 45deg;
}

.principles[data-active="craft"] .principles__visual i:nth-child(4) {
  --r: -45deg;
}

.principles[data-active="curiosity"] .principles__visual i:nth-child(1) {
  transform: translate(calc(-50% - var(--d-far)), calc(-50% - var(--d) * 0.3))
    rotate(12deg);
}

.principles[data-active="curiosity"] .principles__visual i:nth-child(2) {
  transform: translate(calc(-50% + var(--d) * 0.6), calc(-50% - var(--d-far)))
    rotate(96deg);
}

.principles[data-active="curiosity"] .principles__visual i:nth-child(3) {
  transform: translate(
      calc(-50% + var(--d-far) * 0.9),
      calc(-50% + var(--d) * 0.73)
    )
    rotate(204deg);
}

.principles[data-active="curiosity"] .principles__visual i:nth-child(4) {
  transform: translate(calc(-50% - var(--d) * 0.4), calc(-50% + var(--d-far)))
    rotate(308deg);
}

.principles__content {
  align-self: center;
  padding: 120px var(--side) 100px;
}

.principles__content > .eyebrow {
  margin-bottom: 30px;
  color: var(--signal);
}

.principles__content h2 {
  max-width: 720px;
  font-size: clamp(48px, 6vw, 94px);
  font-weight: 800;
  letter-spacing: -0.06em;
  line-height: 0.96;
}

.principle-tabs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  margin-top: 62px;
  border-top: 1px solid var(--line-light);
  border-left: 1px solid var(--line-light);
}

.principle-tabs button {
  padding: 18px 16px;
  border: 0;
  border-right: 1px solid var(--line-light);
  border-bottom: 1px solid var(--line-light);
  background: transparent;
  color: var(--ivory);
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
  text-align: left;
  transition:
    background 220ms ease,
    color 220ms ease;
}

.principle-tabs button:hover,
.principle-tabs button.is-active {
  background: var(--signal);
  color: var(--ink);
}

/* Kept separate from :hover/.is-active — sharing that block meant focusing the
   already-selected tab produced no visible change at all (WCAG 2.4.7). */
.principle-tabs button:focus-visible {
  outline: 2px solid var(--ivory);
  outline-offset: -5px;
}

.principle-tabs button.is-active:focus-visible {
  outline-color: var(--ink);
}

.principle-copy {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: 42px;
  margin-top: 46px;
}

.principle-copy__lead {
  font-size: clamp(22px, 2.4vw, 38px);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.06;
}

.principle-copy__body {
  font-size: 15px;
  line-height: 1.55;
  opacity: 0.6;
}

.contact {
  min-height: 100vh;
  min-height: 100svh;
  padding: calc(var(--header) + 44px) var(--side) 34px;
  background: var(--signal);
  color: var(--ink);
}

.contact__top,
.contact__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.contact__top {
  padding-bottom: 24px;
  border-bottom: 1px solid rgba(21, 22, 27, 0.28);
}

.contact__top a {
  /* Padding, not just font-size: at 9-19px tall these footer links were far
     under the 24px touch target floor (WCAG 2.5.8). */
  padding: 6px 0;
  font-size: clamp(16px, 1.6vw, 24px);
  font-weight: 700;
}

.contact__statement {
  max-width: 1280px;
  margin-top: clamp(90px, 15vh, 170px);
  /* 70px floor clipped "DIRECTION." at 320px, and overflow-x: clip makes the
     lost text unrecoverable (WCAG 1.4.10 Reflow). */
  font-size: clamp(44px, 11vw, 176px);
  font-weight: 800;
  letter-spacing: -0.075em;
  line-height: 0.84;
}

.contact__statement span {
  display: block;
  color: var(--ivory);
}

.contact__bottom {
  margin-top: 94px;
  padding-top: 24px;
  border-top: 1px solid rgba(21, 22, 27, 0.28);
  font: 700 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.08em;
}

/* "Return to signal" measured 110x9px — unhittable with a thumb. */
.contact__bottom a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 8px 0;
}

/* Desktop nav links were 13px tall; the mobile overlay already gets this right. */
.topbar__nav a {
  padding: 6px 0;
}

/* Without flex gap the desktop menu renders as one run of letters. The margin
   is the fallback; @supports removes it wherever gap actually works. */
.topbar__nav a + a {
  margin-left: 28px;
}

@supports (gap: 1px) {
  .topbar__nav a + a {
    margin-left: 0;
  }
}

.topbar__nav a::after {
  bottom: -1px;
}

/* Current section, mirrored from aria-current so it is not colour-only. */
.topbar__nav a.is-current {
  opacity: 1;
}

.topbar__nav a.is-current::after {
  transform: scaleX(1);
  transform-origin: left;
  background: var(--signal);
}

[data-reveal] {
  transform: translateY(42px);
  opacity: 0;
  transition:
    transform 900ms var(--ease),
    opacity 600ms ease;
}

[data-reveal].is-visible {
  transform: none;
  opacity: 1;
}

/* Without JavaScript nothing ever adds .is-visible, so every [data-reveal]
   block would stay at opacity 0 — the studio copy and the whole world index
   would be invisible. Everything below keeps the page readable and navigable
   when script.js does not run. */
.no-js [data-reveal] {
  transform: none;
  opacity: 1;
}

.no-js .cursor-signal,
.no-js .progress,
.no-js .section-index,
.no-js .field__scan,
.no-js .field__exit {
  display: none;
}

.no-js .field {
  height: auto;
  min-height: 0;
}

.no-js .field__sticky {
  position: relative;
  display: grid;
  align-content: center;
  height: auto;
  min-height: 100vh;
  min-height: 100svh;
  overflow: visible;
  padding: calc(var(--header) + 64px) var(--side) 96px;
}

/* The copy leaves absolute positioning so the un-animated phase words can grow
   the hero instead of being clipped by it. */
.no-js .field__copy {
  position: static;
  width: auto;
  transform: none;
  opacity: 1;
}

.no-js .phase-word {
  height: auto;
  overflow: visible;
}

.no-js .phase-word span {
  position: static;
  transform: none;
  opacity: 1;
}

/* IDEAS / SYSTEMS / WORLDS read as one line instead of a stacked animation. */
.no-js .phase-word {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.36em;
  font-size: 0;
}

.no-js .phase-word span {
  font-size: clamp(30px, 4.6vw, 74px);
}

.no-js .method,
.no-js .method__sticky {
  position: relative;
  height: auto;
  min-height: 0;
  display: block;
  overflow: visible;
}

.no-js .method__intro {
  margin-bottom: 66px;
}

.no-js .method__stack {
  display: grid;
  gap: 14px;
  height: auto;
}

.no-js .method-card {
  position: relative;
  min-height: 440px;
  transform: none;
  opacity: 1;
}

.no-js .method__meter {
  display: none;
}

/* body.is-loading sets cursor: wait and only script.js removes it. */
.no-js body {
  cursor: default;
}

/* Hidden while the script is running; the tab panel shows these instead. */
.principle-fallback {
  display: none;
}

.no-js .principle-fallback {
  display: grid;
  gap: 6px 0;
  margin-top: 40px;
  border-top: 1px solid var(--line-light);
  padding-top: 28px;
}

.no-js .principle-fallback dt {
  margin-top: 18px;
  font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.11em;
  color: var(--signal);
}

.no-js .principle-fallback dd {
  margin: 0;
  max-width: 62ch;
  font-size: 15px;
  line-height: 1.55;
  opacity: 0.75;
}

/* The tabs cannot do anything without the script. */
.no-js .principle-tabs {
  display: none;
}

@media (max-width: 980px) {
  :root {
    --header: 62px;
  }

  .cursor-signal,
  .section-index {
    display: none;
  }

  .topbar {
    grid-template-columns: 1fr auto;
  }

  .nav-toggle {
    display: inline-flex;
  }

  .topbar__meta {
    display: none;
  }

  /* The nav becomes a full-screen overlay instead of disappearing. Hidden with
     visibility (not display) so it can animate and so keyboard focus cannot
     reach the links while it is closed. */
  .topbar__nav {
    position: fixed;
    z-index: 119;
    /* Long-hand first: without inset support the overlay collapses into the
       topbar grid and two of the five links land off-screen. */
    top: var(--header);
    right: 0;
    bottom: 0;
    left: 0;
    inset: var(--header) 0 0;
    display: flex;
    flex-direction: column;
    gap: 0;
    padding: clamp(28px, 6vh, 64px) var(--side) var(--side);
    overflow-y: auto;
    visibility: hidden;
    opacity: 0;
    background: var(--ink);
    font-size: clamp(30px, 7vw, 54px);
    font-weight: 800;
    letter-spacing: -0.045em;
    text-transform: none;
    /* visibility is discrete: a plain 300ms transition keeps it `hidden` for the
       whole duration, so the overlay never appeared. Delay it on close only. */
    transition:
      opacity 300ms ease,
      visibility 0s linear 300ms;
  }

  body.nav-open .topbar__nav {
    visibility: visible;
    opacity: 1;
    transition:
      opacity 300ms ease,
      visibility 0s;
  }

  /* Critical: backdrop-filter on .topbar makes it a containing block for
     position: fixed descendants, which collapsed this overlay into the 62px
     bar. Dropping the filter while the menu is open restores the viewport as
     the containing block. The bar also goes opaque, since the blur has nothing
     meaningful to sample behind a full-screen panel. */
  body.nav-open .topbar {
    background: var(--ink);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  /* The overlay keeps its own dark surface even while the bar is in light mode. */
  body.is-light .topbar__nav {
    color: var(--ivory);
  }

  .topbar__nav a {
    padding: clamp(12px, 2.1vh, 20px) 0;
    border-bottom: 1px solid var(--line-light);
    opacity: 1;
  }

  .topbar__nav a::after {
    display: none;
  }

  .topbar__nav a:focus-visible {
    outline: 1px solid var(--signal);
    outline-offset: 3px;
  }

  .topbar__nav-meta {
    display: block;
    margin-top: auto;
    padding-top: 34px;
    font: 700 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.11em;
    opacity: 0.58;
  }

  /* Stop background scroll while the overlay is open. */
  body.nav-open {
    overflow: hidden;
  }

  .field__mark {
    --mark-x: 70%;
    --mark-opacity: 0.64;
    top: 59%;
    width: 80vw;
  }

  .field__copy {
    top: 40%;
    width: calc(100% - var(--side) * 2);
  }

  .field__coordinates {
    display: none;
  }

  .thesis {
    grid-template-columns: 1fr;
    align-content: center;
    gap: 70px;
  }

  .thesis__body {
    grid-template-columns: repeat(2, 1fr);
    padding: 0 0 80px;
  }

  .thesis__body p + p {
    padding: 0 0 0 30px;
    border-top: 0;
    border-left: 1px solid var(--line-dark);
  }

  .method__sticky {
    grid-template-columns: 0.72fr 1.28fr;
    gap: 36px;
  }

  .method-card small {
    grid-column: 1 / -1;
    justify-self: start;
  }

  .world-grid {
    grid-template-columns: 1fr;
  }

  .world-card {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    min-height: 390px;
  }

  .world-card__visual {
    /* 1 / -1 spans the real rows; 1 / 5 invented a fourth ghost row that
       squeezed the card text into the top ~106px. */
    grid-row: 1 / -1;
    height: 350px;
    margin: 0 34px 0 0;
  }

  .world-card h3 {
    align-self: end;
  }

  .principles {
    grid-template-columns: 1fr;
  }

  .principles__visual {
    min-height: 52vh;
    min-height: 52svh;
    border-right: 0;
    border-bottom: 1px solid var(--line-light);
  }
}

@media (max-width: 680px) {
  .field {
    height: 340vh;
    min-height: 2200px;
  }

  .field__grid {
    background-size: 25vw 25vw;
  }

  .field__mark {
    --mark-x: 58%;
    top: 63%;
    width: 112vw;
  }

  .field__copy {
    top: 37%;
  }

  .phase-word {
    height: 68px;
  }

  /* The third column ("SCROLL TO PROCESS") used to be hidden here, which left a
     context-free "01 / INPUT" as the only hint on the tallest section of the
     site. Kept, just tighter. */
  .field__readout {
    gap: 10px;
    font-size: 8px;
  }

  .thesis {
    min-height: auto;
    padding-top: 120px;
  }

  .thesis__body {
    display: block;
  }

  .thesis__body p + p {
    margin-top: 28px;
    padding: 28px 0 0;
    border-top: 1px solid var(--line-dark);
    border-left: 0;
  }

  .thesis__signature {
    gap: 8px;
    font-size: 7px;
  }

  .method {
    height: auto;
    min-height: 0;
  }

  .method__sticky {
    position: relative;
    display: block;
    height: auto;
    min-height: 0;
    overflow: visible;
    padding-top: 120px;
  }

  .method__intro {
    margin-bottom: 66px;
  }

  .method__stack {
    display: grid;
    gap: 14px;
    height: auto;
  }

  .method-card {
    position: relative;
    min-height: 440px;
    transform: none !important;
    opacity: 1 !important;
  }

  /* script.js skips renderMethod below 681px, so the meter would sit at
     scaleX(0) forever. */
  .method__meter {
    display: none;
  }

  .world-index {
    padding-bottom: 80px;
  }

  .world-index__header {
    display: block;
    padding: 90px 0 58px;
  }

  .world-index__header .eyebrow {
    margin-bottom: 24px;
  }

  .world-card {
    display: block;
    min-height: 560px;
  }

  .world-card__visual {
    height: 310px;
    margin: 32px 0 40px;
  }

  .principles__visual {
    min-height: 48vh;
    min-height: 48svh;
  }

  /* The per-breakpoint offset overrides are gone: --d/--d-far are already
     viewport-relative, and these lower-specificity rules could not override the
     [data-active] states anyway — which is how the curiosity layout ended up
     throwing all four diamonds outside the box on small screens. */

  .principles__content {
    padding-top: 82px;
    padding-bottom: 82px;
  }

  .principle-tabs,
  .principle-copy {
    grid-template-columns: 1fr;
  }

  .principle-copy {
    gap: 24px;
  }

  .contact__top {
    align-items: flex-start;
    flex-direction: column;
  }

  .contact__statement {
    margin-top: 100px;
  }

  .contact__bottom {
    align-items: flex-start;
    flex-direction: column;
  }
}

@media (any-pointer: coarse) {
  .cursor-signal {
    display: none;
  }
}

/* Forced-colors overrides background, so the selected principle tab lost its
   only distinguishing mark and all four looked identical. */
@media (forced-colors: active) {
  .principle-tabs button.is-active {
    border-left: 4px solid Highlight;
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
  }

  .nav-toggle__mark,
  .wordmark__mark {
    forced-color-adjust: none;
    background: Highlight;
  }

  .topbar__nav a.is-current::after {
    background: Highlight;
  }
}

/* Landscape phones and short desktop windows. The hero centres its copy on the
   sticky box, which starts at y=0 behind the fixed topbar — at 390px tall the
   eyebrow and the top of the phase word ended up underneath the bar. Type also
   has to be capped against the viewport height, not just its width: at 844x390
   the width-based clamp still asks for ~88px type. */
@media (max-height: 640px) {
  .field__copy {
    /* Centre within the space below the bar rather than the whole box. */
    top: calc(50% + var(--header) / 2);
  }

  .phase-word {
    height: min(clamp(50px, 11vw, 170px), 17vh);
  }

  .phase-word span {
    font-size: min(clamp(46px, 11vw, 174px), 16vh);
  }

  .field h1 {
    margin-top: 4px;
    font-size: min(clamp(46px, 10.4vw, 165px), 16vh);
  }

  .field__copy .eyebrow {
    margin-bottom: clamp(10px, 2vh, 24px);
  }

  .field__readout {
    bottom: 14px;
  }

  .field__coordinates {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }

  .field {
    height: 100vh;
    height: 100svh;
    min-height: 680px;
  }

  .field__mark {
    --mark-travel: 0;
    --mark-visibility: 1;
    --mark-scale: 0.88;
    --mark-rotate: 0deg;
    --mark-gray: 0;
    --mark-bright: 1;
  }

  .field__scan,
  .field__exit {
    display: none;
  }

  .method {
    height: auto;
    min-height: 0;
  }

  .method__sticky {
    position: relative;
    display: block;
    height: auto;
    min-height: 0;
    overflow: visible;
  }

  .method__intro {
    margin-bottom: 70px;
  }

  .method__stack {
    display: grid;
    gap: 12px;
    height: auto;
  }

  .method-card {
    position: relative;
    min-height: 480px;
    transform: none !important;
    opacity: 1 !important;
  }

  [data-reveal] {
    transform: none;
    opacity: 1;
  }
}

/* Everything on this site is ivory or orange on near-black. Printed as-is the
   headings, the Method intro, the whole Principles column and the closing
   statement come out white on white — invisible. The pinned scroll sections
   also have to unwind into normal flow or the document runs to dozens of
   near-empty pages. */
@media print {
  *,
  *::before,
  *::after {
    background: transparent !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }

  .topbar,
  .section-index,
  .cursor-signal,
  .progress,
  .nav-toggle,
  .skip-link,
  .field__grid,
  .field__cross,
  .field__scan,
  .field__exit,
  .field__mark,
  .field__coordinates,
  .field__readout,
  .method__meter,
  .thesis__signature,
  .ticker,
  .principles__visual,
  .world-card__visual {
    display: none !important;
  }

  .field,
  .method {
    height: auto !important;
    min-height: 0 !important;
  }

  .field__sticky,
  .method__sticky,
  .method__stack,
  .field__copy,
  .method-card {
    position: static !important;
    display: block !important;
    height: auto !important;
    min-height: 0 !important;
    overflow: visible !important;
    transform: none !important;
    opacity: 1 !important;
  }

  .phase-word {
    height: auto !important;
    overflow: visible !important;
  }

  .phase-word span {
    position: static !important;
    display: inline !important;
    transform: none !important;
    opacity: 1 !important;
    font-size: 20pt !important;
  }

  [data-reveal] {
    transform: none !important;
    opacity: 1 !important;
  }

  /* Show all four principles: the tabs cannot be operated on paper. */
  .principle-fallback {
    display: block !important;
  }

  .principle-tabs {
    display: none !important;
  }

  h1 {
    font-size: 28pt !important;
  }

  h2 {
    font-size: 18pt !important;
  }

  h3 {
    font-size: 14pt !important;
  }

  p,
  dd,
  small {
    font-size: 11pt !important;
  }

  section,
  .method-card,
  .world-card {
    page-break-inside: avoid;
  }

  /* Contact link is the one thing worth carrying off the page. */
  .contact__top a::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
  }
}
