/* ═══════════════════════════════════════════════════════════════════════════
   rox.ae · shared stylesheet
   Every page on the site loads this once. Tokens, the five-palette
   contract, type, layout, nav and menu, hero, every component, motion.
   Page-specific rules live in each page's own <style> block, after this.
   Rules that must not be broken (CLAUDE.md): every colour from a token,
   one typeface one weight, zero box-shadow, no em dashes, body 16px floor,
   mono 13px, touch targets 44px, no horizontal overflow at 320px.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Fonts ──────────────────────────────────────────────────────────────── */
@font-face {
  font-family: 'Aspekta';
  src: url('fonts/Aspekta-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Roboto Mono Local';
  src: url('fonts/RobotoMono-400.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ── Tokens ─────────────────────────────────────────────────────────────────
   Forest, the load state of the homepage and the OG card. A page that
   loads on another palette overrides this block inline, in its own head,
   so the first paint already carries the right colours. The click shuffle
   rewrites the same properties on the html element. A hex value written
   anywhere else on the site is stranded when the palette moves. */
:root {
  --accent:     #cef79e;
  --accent-rgb: 206, 247, 158;
  --ink:      #222f30;
  --bone:     #f7f7f5;
  --paper:    #ffffff;
  --graphite: #4d5757;
  --lichen:   #c9cbbe;
  --void:     #000000;

  --ramp-0: #162d1f;
  --ramp-1: #32533e;
  --ramp-2: #83a38a;
  --ramp-3: #bfa37a;
  --ramp-4: #ddd7ca;

  /* Secondary text on ink (5.15:1) and on black (4.8:1). Graphite stays for
     hairlines on dark and for all text on light. See design.md §4. */
  --dark-2:   #a8b0ad;
  --void-2:   #717b79;

  --font-sans: 'Aspekta', 'Inter Tight', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'Roboto Mono Local', 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

  --max: 1200px;
  --pad: 24px;
  --section-y: clamp(80px, 10vw, 120px);
}

/* ── Reset ──────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.3;
  letter-spacing: -0.001em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; padding: 0; }
ul, ol { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
input, textarea, select { font: inherit; }

/* One typeface, one weight. Hierarchy is size, line-height and tracking. */
h1, h2, h3, h4, strong, b, th { font-weight: 400; }

:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ── Layout ─────────────────────────────────────────────────────────────── */
/* width:100% keeps this full-bleed inside flex parents; auto cross-axis
   margins otherwise collapse it to shrink-to-fit. Paid for once. */
.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding-inline: var(--pad); }
.band { position: relative; padding-block: var(--section-y); }
.band--dark  { background: var(--ink); }
.band--light { background: var(--bone); color: var(--ink); }
.band--void  { background: var(--void); }
.band > .wrap, .hero__inner { position: relative; z-index: 1; }

/* ── Ambient orbs, dark bands only ──────────────────────────────────────── */
.orbs {
  position: absolute; inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}
.orb {
  position: absolute;
  border-radius: 50%;
  will-change: transform;
  /* Nine stops stand in for a wide blur: coarse stops band as rings at
     these luminances. --accent-rgb because rgba() cannot take a hex token. */
  background: radial-gradient(circle closest-side,
      rgba(var(--accent-rgb),1)    0%,
      rgba(var(--accent-rgb),0.78) 14%,
      rgba(var(--accent-rgb),0.56) 27%,
      rgba(var(--accent-rgb),0.37) 40%,
      rgba(var(--accent-rgb),0.22) 53%,
      rgba(var(--accent-rgb),0.12) 66%,
      rgba(var(--accent-rgb),0.05) 79%,
      rgba(var(--accent-rgb),0.01) 90%,
      rgba(var(--accent-rgb),0)    100%);
}
.orb--1 { width: 640px; height: 640px; top: -8%;  left: -6%;  opacity: 0.070; animation: drift-1 68s ease-in-out infinite; }
.orb--2 { width: 480px; height: 480px; top: 34%;  right: -8%; opacity: 0.050; animation: drift-2 87s ease-in-out infinite; }
.orb--3 { width: 700px; height: 700px; bottom: -14%; left: 22%; opacity: 0.045; animation: drift-3 54s ease-in-out infinite; }
.orb--4 { width: 400px; height: 400px; top: 8%;   left: 46%;  opacity: 0.040; animation: drift-4 76s ease-in-out infinite; }
.orbs::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
@keyframes drift-1 {
  0%   { transform: translate3d(0,0,0) scale(1); }
  33%  { transform: translate3d(7vw, 5vh, 0) scale(1.09); }
  66%  { transform: translate3d(2vw, 11vh, 0) scale(0.96); }
  100% { transform: translate3d(0,0,0) scale(1); }
}
@keyframes drift-2 {
  0%   { transform: translate3d(0,0,0) scale(1); }
  40%  { transform: translate3d(-6vw, 8vh, 0) scale(1.12); }
  70%  { transform: translate3d(-9vw, -4vh, 0) scale(0.94); }
  100% { transform: translate3d(0,0,0) scale(1); }
}
@keyframes drift-3 {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(9vw, -7vh, 0) scale(1.07); }
  100% { transform: translate3d(0,0,0) scale(1); }
}
@keyframes drift-4 {
  0%   { transform: translate3d(0,0,0) scale(1); }
  45%  { transform: translate3d(-5vw, 9vh, 0) scale(1.14); }
  75%  { transform: translate3d(4vw, 4vh, 0) scale(0.97); }
  100% { transform: translate3d(0,0,0) scale(1); }
}

/* ── Typographic roles ──────────────────────────────────────────────────── */
.mono {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.23;
  letter-spacing: -0.02em;
}
.counter {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--dark-2);
  border: 1px solid var(--graphite);
  border-radius: 9999px;
  padding: 9px 15px;
}
.band--light .counter { color: var(--graphite); border-color: var(--lichen); }
.h-section {
  font-size: clamp(30px, 4.5vw, 58px);
  line-height: 1.1;
  letter-spacing: -0.012em;
  margin-top: 28px;
}
.lede {
  font-size: clamp(17px, 1.5vw, 22px);
  line-height: 1.35;
  letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 620px;
  margin-top: 22px;
}
.band--light .lede { color: var(--graphite); }
.body-copy {
  margin-top: clamp(28px, 3.5vw, 40px);
  max-width: 660px;
  display: grid; gap: 18px;
}
.body-copy p {
  font-size: 17px; line-height: 1.5; letter-spacing: -0.006em;
  color: var(--dark-2);
}
.band--light .body-copy p { color: var(--graphite); }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
.dot--plain { background: var(--graphite); }
/* Inline links inside body copy: the only underlines on the site. */
.lede a, .body-copy a, .faq__a a, .fact__text a, .svc__text a, .step__text a, .foot__meta a, .note a {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color 240ms ease;
}
.lede a:hover, .body-copy a:hover, .faq__a a:hover, .fact__text a:hover, .svc__text a:hover, .step__text a:hover, .foot__meta a:hover, .note a:hover { color: var(--accent); }
.band--light .lede a:hover, .band--light .body-copy a:hover, .band--light .fact__text a:hover { color: var(--ink); }

/* ── Nav ────────────────────────────────────────────────────────────────────
   Wordmark left; on the right one plain mono aside (MENU) and one ghost
   pill, the page's primary action. The aside is deliberately not a second
   pill: one primary action per nav. */
.nav {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding-block: 26px;
}
.wordmark { display: inline-flex; align-items: center; }
/* Supplied artwork is white on transparent with lighter grey accent
   diagonals on the R. No filter: recolouring flattens the two tones. */
.wordmark img { height: clamp(19px, 2.1vw, 23px); width: auto; }
.nav__right { display: flex; align-items: center; gap: clamp(12px, 2vw, 20px); }
.nav__aside {
  display: inline-flex; align-items: center; gap: 8px;
  color: rgba(255,255,255,0.72);
  white-space: nowrap;
  transition: color 240ms ease;
}
.nav__aside:hover { color: var(--accent); }
.nav__aside .dot { width: 5px; height: 5px; }
/* 44px both ways on touch: MENU is four letters and a dot, 43px wide alone. */
@media (pointer: coarse) { .nav__aside { padding-block: 15px; min-width: 44px; justify-content: center; } }
.pill-ghost {
  display: inline-flex; align-items: center;
  font-family: var(--font-mono);
  font-size: 13px; line-height: 1; letter-spacing: -0.02em;
  color: var(--paper);
  border: 1px solid var(--graphite);
  border-radius: 9999px;
  padding: 11px 18px;
  white-space: nowrap;
  transition: border-color 240ms ease, color 240ms ease;
}
.pill-ghost:hover { border-color: var(--accent); color: var(--accent); }
.band--light .pill-ghost { color: var(--ink); border-color: var(--lichen); }
.band--light .pill-ghost:hover { border-color: var(--ink); color: var(--ink); }

/* ── Menu overlay ───────────────────────────────────────────────────────────
   The whole site map on one ink surface. Opens from the MENU aside, closes
   on Escape, the CLOSE aside, or any link. Big type for the desks, smaller
   for the pages, a mono contact row at the foot. Lines rise in the hero's
   cadence. Display is gated on .js so a failed script never strands an
   invisible fixed layer over the page. */
.menu {
  position: fixed; inset: 0; z-index: 80;
  display: none;
  flex-direction: column;
  background: var(--ink);
  color: var(--paper);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  opacity: 0;
  visibility: hidden;
  transition: opacity 320ms ease, visibility 0s linear 320ms, background-color 620ms ease;
}
.js .menu { display: flex; }
.menu.is-open { opacity: 1; visibility: visible; transition: opacity 320ms ease, background-color 620ms ease; }
html.menu-open { overflow: hidden; }
.menu__inner { position: relative; z-index: 1; flex: 1; display: flex; flex-direction: column; padding-bottom: clamp(28px, 5vh, 56px); }
.menu .nav { padding-block: 26px; }
.menu__body {
  flex: 1;
  display: grid; gap: clamp(36px, 6vh, 72px) clamp(40px, 6vw, 120px);
  grid-template-columns: 1fr;
  padding-top: clamp(20px, 5vh, 56px);
  align-content: start;
}
@media (min-width: 900px) { .menu__body { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); } }
.menu__label { display: flex; align-items: center; gap: 10px; color: var(--dark-2); margin-bottom: 18px; }
.menu__big a, .menu__small a { display: block; }
.menu__big a {
  font-size: clamp(30px, 5.2vw, 64px);
  line-height: 1.06;
  letter-spacing: -0.026em;
  padding-block: 0.09em;
  transition: color 240ms ease, transform 300ms ease;
}
.menu__small a {
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.25;
  letter-spacing: -0.012em;
  padding-block: 0.16em;
  transition: color 240ms ease, transform 300ms ease;
}
.menu__big a:hover, .menu__small a:hover { color: var(--accent); transform: translateX(6px); }
.menu a[aria-current="page"] { color: var(--accent); }
.menu a[aria-current="page"]::after { content: ' ·'; }
.menu .line { display: block; overflow: hidden; padding-bottom: 0.13em; margin-bottom: -0.13em; }
.menu .line > span { display: block; }
.js .menu .line > span { transform: translateY(105%); }
.js .menu.is-open .line > span {
  transform: none;
  transition: transform 520ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(60ms + var(--i, 0) * 45ms);
}
.menu__foot {
  margin-top: auto;
  padding-top: clamp(28px, 5vh, 48px);
  border-top: 1px solid var(--graphite);
  display: flex; flex-wrap: wrap; gap: 14px clamp(20px, 3vw, 40px);
  color: var(--dark-2);
}
.menu__foot a { transition: color 240ms ease; }
.menu__foot a:hover { color: var(--accent); }
@media (pointer: coarse) { .menu__foot a { padding-block: 14px; margin-block: -14px; display: inline-block; } }

/* ── Arrow chips: the one place the accent fills a shape ────────────────── */
.arrow {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--ink);
}
.arrow svg { width: 17px; height: 17px; transition: transform 300ms ease; }
a:hover > .arrow svg, .arrow:hover svg, a:hover .arrow svg, button:hover .arrow svg { transform: translateX(4px); }
.arrow--down svg { transform: rotate(90deg); }
a:hover > .arrow--down svg, .arrow--down:hover svg { transform: rotate(90deg) translateX(4px); }
/* A ghost chip for secondary rows: hairline, no fill. Fills on hover. */
.arrow--ghost {
  background: transparent;
  color: var(--paper);
  border: 1px solid var(--graphite);
  transition: background-color 240ms ease, color 240ms ease, border-color 240ms ease;
}
a:hover .arrow--ghost { background: var(--accent); color: var(--ink); border-color: var(--accent); }
.band--light .arrow--ghost { color: var(--ink); border-color: var(--lichen); }

/* ── Buttons ────────────────────────────────────────────────────────────── */
/* Buttons take the opposite surface: ink on light bands, paper on dark. */
.btn-fill {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--ink); color: var(--paper);
  border-radius: 8px;
  padding: 15px 22px;
  font-family: var(--font-mono);
  font-size: 13px; line-height: 1; letter-spacing: -0.02em;
  white-space: nowrap;
  transition: opacity 240ms ease;
}
.btn-fill:hover { opacity: 0.82; }
.btn-fill--invert { background: var(--paper); color: var(--ink); }
.btn-fill[disabled] { opacity: 0.5; cursor: default; }
.cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.cta__pair { display: flex; align-items: center; gap: 12px; }
.cta__pair:hover .btn-fill { opacity: 0.82; }
/* Microcopy welded to the button it de-risks. 16px, never below the floor. */
.cta-note {
  margin-top: 14px;
  font-size: 16px; line-height: 1.45; letter-spacing: -0.004em;
  color: var(--dark-2);
  max-width: 560px;
}
.band--light .cta-note { color: var(--graphite); }
.band--void .cta-note { color: var(--void-2); }
/* Mono text link: the quieter CTA voice between filled buttons. */
.link-quiet {
  display: inline-flex; align-items: center; gap: 8px;
  color: rgba(255,255,255,0.72);
  white-space: nowrap;
  transition: color 240ms ease;
}
.link-quiet:hover { color: var(--accent); }
.band--light .link-quiet { color: var(--graphite); }
.band--light .link-quiet:hover { color: var(--ink); }
@media (pointer: coarse) { .link-quiet { padding-block: 15px; } }

/* ── Hero ───────────────────────────────────────────────────────────────────
   The sticky variant pins while the frame opens (landing pages). The
   compact variant is a plain full-bleed band on the same shader for the
   inner pages (work, studio, contact). */
.hero {
  position: relative;
  height: 126vh;
  background: var(--paper);      /* the surround the frame sits in */
}
.hero__sticky { position: sticky; top: 0; height: 100svh; }
.hero__frame {
  position: absolute; inset: 0;
  clip-path: inset(var(--frame-inset, 0px) round var(--frame-radius, 0px));
  overflow: hidden;
  background: var(--ramp-0);
}
.hero__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.hero__fallback {
  position: absolute; inset: 0; display: none;
  background:
    radial-gradient(90% 120% at 88% 62%, var(--ramp-3) 0%, transparent 46%),
    radial-gradient(80% 100% at 66% 30%, var(--ramp-2) 0%, transparent 55%),
    linear-gradient(105deg, var(--ramp-0) 0%, var(--ramp-1) 42%, var(--ramp-2) 100%);
}
.no-webgl .hero__fallback { display: block; }
.hero__layer { position: relative; z-index: 2; height: 100%; display: flex; flex-direction: column; }
@media (max-width: 700px) { .hero { height: 118vh; } }

.hero--compact { height: auto; background: var(--ramp-0); }
.hero--compact .hero__sticky { position: static; height: auto; }
.hero--compact .hero__frame {
  position: relative; inset: auto;
  clip-path: none;
  min-height: 70svh;
  display: flex; flex-direction: column;
}
.hero--compact .hero__layer { flex: 1; }
.hero--compact .hero__inner { padding-bottom: clamp(40px, 6vh, 72px); }

.hero__inner {
  flex: 1;
  display: flex; flex-direction: column;
  justify-content: space-between;
  gap: clamp(28px, 3.5vh, 56px);
  padding-block: clamp(24px, 4vh, 56px) clamp(24px, 3.5vh, 44px);
}
.hero__top { max-width: 1080px; }
/* The vh term stops the headline growing past the fold on short laptop
   viewports. Never remove it. 13.5vh because these heroes carry a button
   and a note under the copy. */
.hero__title {
  font-size: clamp(40px, min(9vw, 13.5vh), 140px);
  line-height: 1.0;
  letter-spacing: -0.03em;
  margin-top: clamp(20px, 2.5vh, 40px);
}
/* Descender room inside the entrance mask: at line-height 1 the tails of
   g, p and y clip once the rise lands. Obvious on a 27-inch monitor. */
.hero__title .line { display: block; overflow: hidden; padding-bottom: 0.13em; margin-bottom: -0.13em; }
.hero__title .line > span { display: block; }
.hero__bottom {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: 32px;
}
.hero__copy { max-width: 620px; }
.hero__copy p {
  font-size: clamp(17px, 1.8vw, 22px);
  line-height: 1.35;
  letter-spacing: -0.008em;
  color: var(--dark-2);
}
.hero__cta { margin-top: clamp(18px, 2.5vh, 28px); }
/* Double-scoped to beat `.hero__copy p` on specificity (design.md §17.3). */
.hero__copy .hero__note { margin-top: 12px; font-size: 16px; line-height: 1.45; }
.hero__copy .hero__meta {
  margin-top: 22px;
  font-size: 13px;
  line-height: 1.55;
  letter-spacing: -0.02em;
}
/* The hero sits on the shader, not ink: hairlines and copy lift a step. */
.hero .counter, .hero .pill-ghost { border-color: rgba(255,255,255,0.34); color: #fff; }
.hero .pill-ghost:hover { border-color: var(--accent); color: var(--accent); }
.hero__copy p { color: rgba(255,255,255,0.90); }
.hero__copy .hero__note { color: rgba(255,255,255,0.80); }
.hero__copy .hero__meta { color: rgba(255,255,255,0.80); }
.hero__title { text-shadow: 0 2px 44px rgba(6,22,14,0.30); }
.hero__hint {
  display: inline-flex; align-items: center; gap: 10px;
  margin-top: 14px;
  color: var(--accent);
  transition: opacity 500ms ease, color 620ms ease;
}
.is-shuffled .hero__hint { opacity: 0; pointer-events: none; }

/* ── Client strip (marquee) ─────────────────────────────────────────────────
   Names set as type, not logos: zero bytes, recolours with the palette.
   The track is cloned once by script for a seamless loop; without script
   or under reduced motion it is a wrapping row. */
.strip {
  position: relative;
  border-top: 1px solid var(--graphite);
  border-bottom: 1px solid var(--graphite);
  padding-block: 22px;
  overflow: hidden;
}
.strip__label { color: var(--dark-2); margin-bottom: 14px; }
.marquee { overflow: hidden; }
.marquee__track {
  display: flex; flex-wrap: wrap;
  gap: 14px clamp(28px, 4vw, 56px);
  color: var(--paper);
  font-size: clamp(19px, 2vw, 26px);
  line-height: 1.2;
  letter-spacing: -0.012em;
}
.marquee__track > span { white-space: nowrap; }
.marquee__track > span::after { content: '·'; margin-left: clamp(28px, 4vw, 56px); color: var(--graphite); }
.js .marquee.is-live .marquee__track {
  flex-wrap: nowrap;
  width: max-content;
  gap: 0;
  animation: marquee var(--marquee-s, 40s) linear infinite;
}
.js .marquee.is-live .marquee__track > span { padding-right: clamp(28px, 4vw, 56px); }
.js .marquee.is-live .marquee__track > span::after { margin-left: clamp(28px, 4vw, 56px); }
.js .marquee.is-live:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }

/* ── Facts: dot label plus one line ─────────────────────────────────────── */
.facts {
  margin-top: clamp(44px, 5vw, 64px);
  display: grid; gap: clamp(28px, 4vw, 44px) clamp(28px, 4vw, 64px);
  grid-template-columns: 1fr;
}
@media (min-width: 560px) { .facts { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 760px) { .facts--three { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 980px) { .facts--four { grid-template-columns: repeat(4, 1fr); } }
.fact__label { display: flex; align-items: center; gap: 10px; color: var(--dark-2); }
.band--light .fact__label { color: var(--graphite); }
.fact__text {
  margin-top: 12px;
  font-size: 17px; line-height: 1.45; letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 340px;
}
.band--light .fact__text { color: var(--graphite); }
/* Big figures with a count-up. The figure is display size; the caption
   sits under it in body. */
.fact__num {
  font-size: clamp(44px, 6vw, 84px);
  line-height: 1.0;
  letter-spacing: -0.03em;
  color: var(--paper);
  margin-top: 14px;
  font-variant-numeric: tabular-nums;
}
.band--light .fact__num { color: var(--ink); }
.fact__num small { font-size: 0.42em; letter-spacing: -0.01em; margin-left: 0.1em; }

/* ── Services index: hairline rows that link to each desk ───────────────── */
.services { margin-top: clamp(48px, 6vw, 72px); }
.svc {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: clamp(16px, 4vw, 48px);
  row-gap: 12px;
  align-items: start;
  padding-block: clamp(26px, 3.4vw, 38px);
  border-top: 1px solid var(--graphite);
}
.svc:last-child { border-bottom: 1px solid var(--graphite); }
.svc__n    { grid-column: 1; grid-row: 1; color: var(--dark-2); padding-top: 8px; }
.svc__name {
  grid-column: 2; grid-row: 1;
  font-size: clamp(24px, 2.6vw, 32px); line-height: 1.15; letter-spacing: -0.014em;
  transition: transform 300ms ease, color 240ms ease;
}
.svc__body { grid-column: 2; min-width: 0; }
.svc__text {
  font-size: 17px; line-height: 1.45; letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 520px;
}
.svc__meta { margin-top: 12px; color: var(--dark-2); }
.svc__link { display: inline-flex; margin-top: 14px; }
.svc__go { grid-column: 3; grid-row: 1; align-self: start; margin-top: 2px; }
@media (min-width: 900px) {
  .svc { grid-template-columns: auto minmax(0, 0.85fr) minmax(0, 1.15fr) auto; }
  .svc__body { grid-column: 3; grid-row: 1; padding-top: 6px; }
  .svc__go { grid-column: 4; }
}
/* A whole row is one link: the name slides, the chip fills. */
a.svc:hover .svc__name { transform: translateX(8px); }
.svc--link { color: inherit; }
.svc-note {
  margin-top: clamp(34px, 4vw, 44px);
  font-size: 16px; line-height: 1.5; letter-spacing: -0.004em;
  color: var(--dark-2);
  max-width: 620px;
}
/* Hairline glyphs beside the desks: the deliverable drawn as an outline.
   Zero image weight, follows the palette. */
.glyph { width: 44px; height: 44px; flex: none; color: var(--dark-2); }
.glyph svg { width: 100%; height: 100%; display: block; }
.svc__n--glyph { padding-top: 0; }

/* ── Work grid and reels ────────────────────────────────────────────────── */
.work {
  margin-top: clamp(44px, 5vw, 64px);
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(78vw, 300px);
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.work::-webkit-scrollbar { display: none; }
@media (min-width: 900px) {
  .work {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-columns: auto;
    overflow: visible;
    row-gap: 28px;
  }
  .work--two { grid-template-columns: repeat(2, 1fr); }
}
.work__item { display: block; min-width: 0; }
.work__frame {
  position: relative; display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border: 1px solid var(--graphite);
  border-radius: 8px;
  background: linear-gradient(120deg, var(--ramp-1) 0%, var(--ramp-2) 100%);
  isolation: isolate;
}
.work__frame img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 700ms ease, opacity 500ms ease;
}
.work__item:hover .work__frame img { transform: scale(1.04); }
.js .work__frame img, .js .reel__frame img { opacity: 0; }
.js .work__frame img.is-loaded, .js .reel__frame img.is-loaded { opacity: 1; }
.work__frame iframe {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%;
  border: 0; display: block;
}
.work__play {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--ink);
}
.work__play svg { width: 15px; height: 15px; }
.work__item.is-playing .work__play { display: none; }
.work__cap {
  margin-top: 10px;
  color: var(--dark-2);
  display: flex; justify-content: space-between; gap: 10px;
}
.work-note { margin-top: 14px; color: var(--dark-2); }

.reels {
  margin-top: clamp(28px, 3.5vw, 40px);
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(132px, 34vw, 168px);
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.reels::-webkit-scrollbar { display: none; }
.reels--grid { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); grid-auto-columns: auto; overflow: visible; }
@media (min-width: 560px) { .reels--grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 900px) { .reels--grid { grid-template-columns: repeat(6, 1fr); } }
.reel { display: block; min-width: 0; }
.reel__frame {
  position: relative; display: block;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  border: 1px solid var(--graphite);
  border-radius: 8px;
  background: var(--ramp-0);
}
.reel__frame img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 700ms ease, opacity 500ms ease;
}
.reel:hover .reel__frame img { transform: scale(1.04); }
.reel__play {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--ink);
}
.reel__play svg { width: 13px; height: 13px; }
.reel--more .reel__frame {
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  background: linear-gradient(160deg, var(--ramp-0) 0%, var(--ramp-1) 100%);
  color: var(--paper);
  padding: 14px;
  transition: border-color 240ms ease, background-color 620ms ease, color 620ms ease;
}
.reel--more:hover .reel__frame { border-color: var(--accent); }
.reels-note { margin-top: 14px; color: var(--dark-2); }

/* ── Process steps with the drawn rail ──────────────────────────────────── */
.timeline { margin-top: clamp(48px, 6vw, 72px); position: relative; }
/* Geometry is set in JS from the real node centres: an inline SVG is a
   replaced element and collapses to 0 height when positioned in CSS. */
.timeline__rail { position: absolute; pointer-events: none; overflow: visible; }
.timeline__rail line { stroke: var(--graphite); stroke-width: 1; transition: stroke-dashoffset 1200ms ease-out; }
.steps { display: grid; gap: 40px; }
.step__node {
  width: 13px; height: 13px;
  border: 1px solid var(--graphite);
  border-radius: 50%;
  background: var(--ink);
  position: relative; z-index: 1;
}
.step__label { margin-top: 22px; display: flex; align-items: center; gap: 10px; color: var(--dark-2); }
.step__text {
  margin-top: 12px;
  font-size: 17px; line-height: 1.45; letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 280px;
}
@media (min-width: 860px) { .steps { grid-template-columns: repeat(4, 1fr); gap: 32px; } }
@media (max-width: 859px) {
  .steps { grid-template-columns: 1fr; gap: 34px; padding-left: 34px; }
  .step { position: relative; }
  .step__node { position: absolute; left: -34px; top: 3px; }
  .step__label { margin-top: 0; }
  .step__text { max-width: none; }
}

/* ── FAQ ────────────────────────────────────────────────────────────────── */
.faq { margin-top: clamp(44px, 5vw, 64px); max-width: 760px; }
.faq__item { border-top: 1px solid var(--graphite); padding-block: clamp(24px, 3vw, 32px); }
.faq__item:last-child { border-bottom: 1px solid var(--graphite); }
.faq__q { font-size: clamp(19px, 1.8vw, 23px); line-height: 1.25; letter-spacing: -0.01em; }
.faq__a {
  margin-top: 12px;
  font-size: 17px; line-height: 1.5; letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 640px;
}
.band--light .faq__item { border-color: var(--lichen); }
.band--light .faq__a { color: var(--graphite); }

/* ── Deliverable list: mono key, sans value ─────────────────────────────── */
.terms { margin-top: clamp(40px, 5vw, 56px); max-width: 860px; }
.term {
  display: flex; flex-wrap: wrap; gap: 8px clamp(24px, 6vw, 72px);
  padding-block: clamp(20px, 2.4vw, 26px);
  border-top: 1px solid var(--graphite);
}
.term:last-child { border-bottom: 1px solid var(--graphite); }
.term__k { flex: none; width: 150px; color: var(--dark-2); padding-top: 3px; }
.term__v {
  font-size: 17px; line-height: 1.45; letter-spacing: -0.006em;
  color: var(--dark-2);
  max-width: 620px;
}
.band--light .term { border-color: var(--lichen); }
.band--light .term__k, .band--light .term__v { color: var(--graphite); }
@media (max-width: 620px) {
  .term { flex-direction: column; gap: 8px; }
  .term__k { width: auto; padding-top: 0; }
}

/* ── Big statement (manifesto) ──────────────────────────────────────────── */
.statement {
  margin-top: clamp(36px, 5vw, 56px);
  font-size: clamp(24px, 3.2vw, 44px);
  line-height: 1.18;
  letter-spacing: -0.018em;
  max-width: 980px;
}
.statement .muted { color: var(--dark-2); }
.band--light .statement .muted { color: var(--graphite); }

/* ── The brief: the lead form ───────────────────────────────────────────────
   Six fields, most of them taps. Posts JSON to /api/brief.php and lands on
   /thanks/; without script it posts as a normal form to the same endpoint.
   The WhatsApp link beneath composes the same brief into a chat opener.
   Inputs take 16px so iOS never zooms the page to focus them. */
.brief {
  margin-top: clamp(36px, 4.5vw, 52px);
  max-width: 760px;
  display: grid; gap: 22px;
}
.brief__row { display: grid; gap: 22px; }
@media (min-width: 700px) { .brief__row--2 { grid-template-columns: 1fr 1fr; } }
.brief__label { display: flex; align-items: center; gap: 10px; color: var(--dark-2); margin-bottom: 10px; }
/* The optional hint shares the label's tone: graphite measured 2.8:1 on black. */
.brief__label .opt { color: var(--dark-2); }
.pills { display: flex; flex-wrap: wrap; gap: 10px; }
/* The real control stays in the tree for keyboard and screen readers; the
   pill label is its visible body. */
.pills input {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}
.pills .pill-ghost { cursor: pointer; }
.pills input:checked + .pill-ghost { border-color: var(--accent); color: var(--accent); }
.pills input:focus-visible + .pill-ghost { outline: 1px solid var(--accent); outline-offset: 3px; }
.field {
  width: 100%;
  background: transparent;
  border: 1px solid var(--graphite);
  border-radius: 8px;
  color: var(--paper);
  padding: 14px 16px;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.4;
  letter-spacing: -0.004em;
  transition: border-color 240ms ease, color 620ms ease, background-color 620ms ease;
}
.field::placeholder { color: var(--dark-2); opacity: 0.7; }
.field:focus { border-color: var(--accent); outline: none; }
.field[aria-invalid="true"] { border-color: var(--accent); }
textarea.field { min-height: 120px; resize: vertical; }
/* Honeypot: present in the tree for bots, zero-sized and inert for people
   and for the layout audit (which skips zero-height elements). */
.brief__hp { position: absolute; width: 0; height: 0; overflow: hidden; opacity: 0; pointer-events: none; }
.brief__err { display: none; color: var(--accent); margin-top: 8px; }
.brief.is-invalid .brief__err { display: block; }
.brief__send { margin-top: 6px; }
.brief__alt { margin-top: 4px; }
/* The state after sending, and the honest fallback when the endpoint
   fails: never claim the brief arrived when it did not. */
.brief__done { display: none; margin-top: clamp(36px, 4.5vw, 52px); max-width: 640px; }
.brief__done.is-on { display: block; }
.brief__done .h-section { margin-top: 0; }
.brief__out {
  width: 100%; margin-top: 16px; min-height: 160px;
  font-family: var(--font-mono); font-size: 13px; line-height: 1.6; letter-spacing: -0.02em;
  color: var(--dark-2); background: transparent;
  border: 1px solid var(--graphite); border-radius: 8px; padding: 14px 16px;
}

/* ── Sticky action bar, phones only ─────────────────────────────────────────
   Shows once the hero button has scrolled away, hides while the brief or
   the footer is on screen. Accent surface, ink text, hairline on top. */
.stickybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: none;
  align-items: center; justify-content: center; gap: 10px;
  background: var(--accent); color: var(--ink);
  border-top: 1px solid var(--graphite);
  padding: 17px var(--pad);
  padding-bottom: calc(17px + env(safe-area-inset-bottom, 0px));
  font-family: var(--font-mono);
  font-size: 13px; line-height: 1; letter-spacing: -0.02em;
  transform: translateY(102%);
  transition: transform 300ms ease, background-color 620ms ease, color 620ms ease, border-color 620ms ease;
}
.stickybar.is-on { transform: none; }
@media (max-width: 820px) { .js .stickybar { display: flex; } }
@media (prefers-reduced-motion: reduce) { .stickybar { transition: none; } }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.foot__title {
  margin-top: 30px;
  font-size: clamp(38px, 7vw, 75px);
  line-height: 1.05;
  letter-spacing: -0.026em;
}
.foot__line {
  margin-top: 22px;
  font-size: 17px; line-height: 1.5; letter-spacing: -0.006em;
  color: var(--void-2);
  max-width: 560px;
}
/* --void-2 is tuned for black; on an ink band (the contact page's brief) it
   measures 3.2:1, so the line takes the ink-band secondary tone there. */
.band--dark .foot__line { color: var(--dark-2); }
.foot__cta { margin-top: clamp(40px, 5vw, 56px); }
/* The site map: three mono link groups on hairlines, then the legal line. */
.foot__grid {
  margin-top: clamp(56px, 7vw, 88px);
  display: grid; gap: clamp(28px, 4vw, 40px) clamp(28px, 4vw, 64px);
  grid-template-columns: 1fr;
  border-top: 1px solid var(--graphite);
  padding-top: clamp(28px, 4vw, 40px);
}
@media (min-width: 620px) { .foot__grid { grid-template-columns: repeat(3, 1fr); } }
.foot__group .mono { color: var(--void-2); }
.foot__group ul { margin-top: 14px; display: grid; gap: 4px; }
.foot__group li a {
  display: inline-block;
  font-size: 17px; line-height: 1.45; letter-spacing: -0.006em;
  color: var(--paper);
  padding-block: 3px;
  transition: color 240ms ease;
}
.foot__group li a:hover { color: var(--accent); }
.foot__group li a[aria-current="page"] { color: var(--void-2); }
.foot__meta {
  margin-top: clamp(40px, 5vw, 56px);
  color: var(--void-2);
  line-height: 1.6;
}
.foot__meta a { text-decoration: none; }
.foot__note { color: var(--void-2); margin-top: 10px; line-height: 1.6; }
@media (pointer: coarse) {
  .foot__group li a { padding-block: 10px; min-width: 44px; }
  .term__v a { display: inline-block; padding-block: 10px; margin-block: -10px; }
  .foot__meta a { display: inline-block; padding-block: 14px; margin-block: -14px; }
}

/* ── Palette swap ───────────────────────────────────────────────────────────
   Custom properties do not animate, but the declarations that resolve them
   do. Changing --ink on the root cross-fades every surface at once. */
body, body *:not(svg):not(svg *) {
  transition: background-color 620ms ease, color 620ms ease, border-color 620ms ease;
}
@media (hover: hover) and (pointer: fine) {
  body { cursor: pointer; }
  p, h1, h2, h3, li, dl, a, .wrap, input, textarea, label { cursor: auto; }
  a, .cta__pair, button, label, .pills .pill-ghost { cursor: pointer; }
}

/* ── Pixel wipe out to the game ─────────────────────────────────────────── */
#wipe { position: fixed; inset: 0; z-index: 99; display: grid; pointer-events: none; }
#wipe span { background: var(--ink); visibility: hidden; }

/* ── Motion ─────────────────────────────────────────────────────────────────
   Everything here is gated on .js, set by an inline script in <head>, so a
   failed script leaves the page fully visible and unanimated. */
.js .reveal { opacity: 0; transform: translateY(20px); }
.js .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity 700ms ease-out, transform 700ms ease-out;
}
/* Staggered children: rows rise one after another, 70ms apart. */
.js .reveal--stagger > * { opacity: 0; transform: translateY(16px); }
.js .reveal--stagger.is-in > * {
  opacity: 1; transform: none;
  transition: opacity 600ms ease-out, transform 600ms ease-out;
  transition-delay: calc(var(--i, 0) * 70ms);
}
/* Hairline draw: rows in a .reveal--draw list grow their top rule from the
   left as they land. Borders move to pseudo-elements so the draw can
   animate; the last row draws its bottom rule too. */
.js .reveal--draw > * { border-top-color: transparent; position: relative; }
.js .reveal--draw > :last-child { border-bottom-color: transparent; }
.js .reveal--draw > *::before, .js .reveal--draw > :last-child::after {
  content: ''; position: absolute; left: 0; right: 0; height: 1px;
  background: var(--graphite);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js .band--light .reveal--draw > *::before, .js .band--light .reveal--draw > :last-child::after { background: var(--lichen); }
.js .reveal--draw > *::before { top: -1px; }
.js .reveal--draw > :last-child::after { bottom: -1px; }
.js .reveal--draw.is-in > *::before, .js .reveal--draw.is-in > :last-child::after { transform: none; }
.js .hero__title .line > span { transform: translateY(105%); }
.js.is-loaded .hero__title .line > span {
  transform: none;
  transition: transform 500ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.js.is-loaded .hero__title .line:nth-child(1) > span { transition-delay: 0ms; }
.js.is-loaded .hero__title .line:nth-child(2) > span { transition-delay: 60ms; }
.js.is-loaded .hero__title .line:nth-child(3) > span { transition-delay: 120ms; }
/* The hero copy and nav fade in behind the headline. */
.js .hero__bottom, .js .hero .counter { opacity: 0; transition: opacity 700ms ease-out 260ms; }
.js.is-loaded .hero__bottom, .js.is-loaded .hero .counter { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .orb { animation: none !important; }
  .reveal, .reveal--stagger > *, .hero__title .line > span, .hero__bottom, .hero .counter, .menu .line > span {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
  .reveal--draw > *::before, .reveal--draw > :last-child::after { transform: none !important; transition: none !important; }
  .timeline__rail line { stroke-dashoffset: 0 !important; transition: none !important; }
  .arrow svg, .svc__name, .work__frame img, .reel__frame img { transition: none !important; }
  .js .marquee.is-live .marquee__track { animation: none; }
  html { scroll-behavior: auto; }
}

/* ── Narrow ─────────────────────────────────────────────────────────────── */
@media (max-width: 420px) { :root { --pad: 20px; } }
/* Three items in a 280px row is the tightest the nav ever gets. */
@media (max-width: 360px) {
  .nav { gap: 8px; }
  .nav__right { gap: 8px; }
  .pill-ghost { padding-inline: 12px; }
}

/* ── Short viewports ────────────────────────────────────────────────────────
   The hero is the only band that must fit an exact height. These buy
   vertical room without taking body copy under the 16px floor. */
@media (max-height: 860px) {
  .nav { padding-block: 20px; }
  .hero__inner { padding-block: 18px 14px; gap: 18px; }
  .hero__title { margin-top: 14px; }
  .hero__copy .hero__meta { margin-top: 14px; }
  .hero__cta { margin-top: 14px; }
  .hero__copy .hero__note { margin-top: 10px; }
  .hero__hint { margin-top: 10px; }
}
@media (max-height: 760px) {
  /* The secondary hero link repeats in the form and the sticky bar; on a
     short phone it is the line that pushes the scroll arrow off the frame. */
  .hero__cta .link-quiet { display: none; }
  .nav { padding-block: 18px; }
  .hero__inner { padding-block: 18px 12px; gap: 16px; }
  .hero__bottom { gap: 16px; }
  .hero__copy p { font-size: 16px; }
}
@media (max-height: 620px) {
  .nav { padding-block: 14px; }
  .hero__inner { padding-block: 12px 8px; gap: 12px; }
  .hero__title { font-size: clamp(33px, min(9vw, 11.5vh), 140px); margin-top: 10px; }
  .hero__copy .hero__meta { display: none; }
  .hero__copy .hero__note { margin-top: 8px; }
  .hero__cta { margin-top: 12px; }
  .hero__hint { display: none; }
}
@media (max-height: 480px) {
  .nav { padding-block: 12px; }
  .hero__inner { padding-block: 10px 8px; gap: 10px; }
  .hero__bottom { gap: 12px; }
  .hero__title { font-size: clamp(26px, 11.5vh, 56px); margin-top: 10px; }
  .hero__cta { margin-top: 10px; }
  .hero__copy .hero__note { display: none; }
}
/* The compact hero has no fold to fit, so it keeps its air. */
.hero--compact .hero__title { font-size: clamp(40px, 8vw, 120px); }
@media (max-height: 620px) { .hero--compact .hero__copy .hero__meta, .hero--compact .hero__hint { display: inline-flex; } }

/* ── Touch ──────────────────────────────────────────────────────────────── */
@media (pointer: coarse) {
  .arrow { position: relative; }
  .arrow::after { content: ''; position: absolute; inset: -5px; }
  .btn-fill { padding: 17px 24px; }
  .pill-ghost { padding: 16px 18px; }
  .wordmark { padding-block: 13px; }
}
