/* Design Surrey — motion layer
   Everything here is transform/opacity only, so it runs on the compositor and
   costs nothing measurable on Core Web Vitals. No library.
   The whole file collapses to nothing under prefers-reduced-motion. */

:root {
  --ease: cubic-bezier(.2, .7, .3, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur: .68s;
}

/* ---------- scroll reveal ----------
   .rv is applied by motion.js so the markup stays clean.
   Elements are visible by default if JS never runs. */

.js .rv { opacity: 0; will-change: opacity, transform; }
.js .rv--up      { transform: translateY(22px); }
.js .rv--left    { transform: translateX(-20px); }
.js .rv--scale   { transform: scale(.985); }
.js .rv--rule    { transform: scaleX(0); transform-origin: left; }
/* clip-path wipe retired: if the observer ever missed an element it stayed
   permanently invisible. Images now use opacity + scale, which degrades safely. */
.js .rv--wipe    { transform: scale(.985); }

.js .rv.rv-in {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 0 0);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    clip-path .9s var(--ease-out);
  will-change: auto;
}

/* stagger — set as an inline custom property by the script */
.js .rv.rv-in { transition-delay: var(--rv-delay, 0s); }

/* ---------- section rules draw in ---------- */

.js .services, .js .process, .js .plist, .js .rows, .js .arith,
.js .metrics, .js .caps, .js .beliefs, .js .tiers, .js .results {
  position: relative;
}
.js .rv-rule::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: currentColor; opacity: .18;
  transform: scaleX(0); transform-origin: left;
}
.js .rv-rule.rv-in::before { transform: scaleX(1); transition: transform 1s var(--ease-out) .05s; }

/* ---------- nav ---------- */

.nav { transition: padding .3s var(--ease), background-color .3s var(--ease), box-shadow .3s var(--ease); }
.nav__inner { transition: min-height .3s var(--ease); }
.nav.is-stuck { box-shadow: 0 1px 0 var(--border), 0 10px 30px -22px rgba(14,15,14,.5); }
.nav.is-stuck .nav__inner { min-height: 64px; }

.nav__links a { position: relative; }
.nav__links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 22px; height: 1px;
  background: var(--brass-500); transform: scaleX(0); transform-origin: right;
  transition: transform .34s var(--ease);
}
.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }

/* ---------- logo ---------- */

.logo__mark { transition: transform .4s var(--ease), background-color .2s var(--ease); }
.logo:hover .logo__mark { transform: translateY(-2px) rotate(-3deg); }

/* ---------- buttons ---------- */

.btn { position: relative; overflow: hidden; }
.btn--primary::before, .btn--secondary::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: currentColor; opacity: 0;
  transform: translateY(101%); transition: transform .38s var(--ease-out);
}
.btn--tertiary { background-image: linear-gradient(currentColor, currentColor); background-size: 0% 1px;
  background-repeat: no-repeat; background-position: left 100%; text-decoration: none;
  padding-bottom: 2px; transition: background-size .34s var(--ease); }
.btn--tertiary:hover { background-size: 100% 1px; }

/* ---------- counters ---------- */

.js [data-count] { font-variant-numeric: tabular-nums; }

/* ---------- cards, rows, list items ---------- */

.service, .cap, .belief, .metric, .arith > div, .also article {
  transition: transform .4s var(--ease), background-color .3s var(--ease);
}
.service:hover, .cap:hover, .also article:hover { transform: translateY(-3px); }

.prow, .row { transition: background-color .25s var(--ease), padding-left .3s var(--ease); }
.prow:hover, .row:hover { background: var(--bone-200); padding-left: var(--s3); }
.on-ink .prow:hover, .on-ink .row:hover { background: rgba(251,250,247,.05); }

.tier, .price { transition: transform .4s var(--ease); }
.tier:hover, .price:hover { transform: translateY(-4px); }

/* ---------- case media ---------- */

.case__media, .study__media { overflow: hidden; }
.case__media img, .study__media img { transition: transform .8s var(--ease-out); }
.case:hover .case__media img, .study:hover .study__media img { transform: scale(1.04); }

.case h3, .study h2 { transition: color .25s var(--ease); }
.case:hover h3 { color: var(--brass-700); }

/* ---------- the brass edge draws across on reveal ---------- */

.js .field-draw { position: relative; }
.js .field-draw::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: calc(var(--field-edge) * -1);
  height: var(--field-edge); background: var(--brass-500);
  transform: scaleX(0); transform-origin: left;
}
.js .field-draw.rv-in::after { transform: scaleX(1); transition: transform 1.1s var(--ease-out) .1s; }

/* ---------- section headings: word by word ---------- */

.js .split-word { display: inline-block; opacity: 0; transform: translateY(.5em); }
.js .rv-in .split-word,
.js .split-word.rv-in {
  opacity: 1; transform: none;
  transition: opacity .5s var(--ease), transform .6s var(--ease);
  transition-delay: calc(var(--w, 0) * 42ms);
}

/* ---------- labels tick in ---------- */

.js .label { transition: letter-spacing .5s var(--ease); }

/* ---------- footer columns ---------- */

.footer__col a { display: inline-block; transition: transform .25s var(--ease), color .2s var(--ease); }
.footer__col a:hover { transform: translateX(3px); }

/* ---------- parallax bands ----------
   Transform-driven, not background-attachment: fixed — which janks on iOS and
   costs a repaint per frame. The media layer is over-sized so it can travel
   without ever exposing an edge. */

.px { position: relative; isolation: isolate; overflow: clip; }
.px__media { position: absolute; inset: -18% 0; z-index: 0; will-change: transform; }
.px__media img { width: 100%; height: 100%; object-fit: cover; }
.px__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(90deg, rgba(16,19,18,0.94) 0%, rgba(16,19,18,0.80) 38%, rgba(16,19,18,0.58) 100%),
    linear-gradient(180deg, rgba(16,19,18,0.45) 0%, rgba(16,19,18,0) 40%, rgba(16,19,18,0.55) 100%);
}
.px__inner { position: relative; z-index: 2; }

/* the ink bands that carry no photograph get a slow-moving brass rule instead */
.px--rule::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; z-index: 1;
  background: linear-gradient(90deg, transparent, var(--brass-500) 22%, var(--brass-500) 78%, transparent);
  opacity: .5;
}

/* ---------- scroll progress ---------- */

.progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  background: transparent; pointer-events: none;
}
.progress i {
  display: block; height: 100%; width: 0;
  background: var(--brass-500);
  transform-origin: left;
}

/* ---------- marquee ---------- */

.marquee { overflow: clip; border-block: 1px solid var(--border); padding-block: var(--s5); }
.marquee__track { display: flex; gap: var(--s12); width: max-content; animation: slide 42s linear infinite; }
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee span {
  font-family: var(--font-mono); font-size: var(--label); letter-spacing: .16em;
  text-transform: uppercase; font-weight: 500; color: var(--ink-400); white-space: nowrap;
}
.marquee span::after { content: "·"; margin-left: var(--s12); color: var(--brass-500); }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* labelled variant: a fixed caption on the left, the sectors running past it */
/* The label lines up with the container's left edge rather than the viewport
   gutter, so it sits on the same vertical as every heading on the page. The
   track still runs to the full width — that is the point of a marquee. */
.marquee--labelled {
  display: flex;
  align-items: center;
  gap: var(--s6);
  padding-left: max(var(--gutter), calc((100% - var(--container)) / 2));
  padding-right: var(--gutter);
  overflow: hidden;
}

/* the label sits inside .marquee, so it inherits `.marquee span` — both rules
   below are scoped to the modifier so they outrank it rather than tie */
.marquee--labelled .marquee__label {
  flex: none;
  position: relative;
  padding-right: var(--s6);
  color: var(--brass-700);
  font-weight: 500;
}

/* a brass tick separates the caption from the moving list — and replaces the
   interpunct `.marquee span::after` would otherwise put here */
.marquee--labelled .marquee__label::after {
  content: "";
  position: absolute;
  right: 0;
  top: 50%;
  width: 2px;
  height: 14px;
  margin: -7px 0 0;
  background: var(--brass-500);
}

.marquee__viewport { flex: 1 1 auto; min-width: 0; overflow: clip; }

@media (max-width: 767px) {
  .marquee--labelled { flex-direction: column; align-items: stretch; gap: var(--s3); }
  .marquee--labelled .marquee__label { padding-right: 0; }
  .marquee--labelled .marquee__label::after { display: none; }
}

/* ---------- big statement type ---------- */

.statement {
  font-size: clamp(28px, 4.2vw, 58px);
  line-height: 1.12; letter-spacing: -.035em; font-weight: 600;
  max-width: 20ch; text-wrap: balance;
}
.statement em { font-style: normal; color: var(--brass-500); }

/* ---------- reduce ---------- */

@media (prefers-reduced-motion: reduce) {
  .js .rv, .js .split-word { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .js .rv-rule::before, .js .field-draw::after { transform: scaleX(1) !important; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
