/* ==========================================================
   Studio Name — Architectural Bureau
   Reference viewport: 1512px. Display type is fluid (vw).
   ========================================================== */

@font-face{
  font-family:"Nimbus Sans L";
  src:url("../fonts/nimbus-sans-l-regular.otf") format("opentype");
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Nimbus Sans L";
  src:url("../fonts/nimbus-sans-l-regular-italic.otf") format("opentype");
  font-weight:400; font-style:italic; font-display:swap;
}
@font-face{
  font-family:"Nimbus Sans L";
  src:url("../fonts/nimbus-sans-l-bold.otf") format("opentype");
  font-weight:700; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Nimbus Sans L";
  src:url("../fonts/nimbus-sans-l-bold-italic.otf") format("opentype");
  font-weight:700; font-style:italic; font-display:swap;
}

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

/* Visually hidden, still read aloud. */
.u-hidden{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap;
}

:root{
  --pad: 28px;

  --paper:#ffffff;
  --ink:#0d0d0d;
  /* All three uses of --muted are caption text at --micro (11-13px), where
     #8c8c8c measured 3.36:1 on white — under AA. #767676 is 4.54:1 and still
     reads as a grey, not a second black. */
  --muted:#767676;

  --void:#000000;
  --ink-i:#ffffff;
  --muted-i:#6e6e6e;

  --ph:#8f8f8f;
  --ph-dark:#333333;

  --sans:"Nimbus Sans L","Helvetica Neue",Helvetica,Arial,sans-serif;
  /* Source Serif 4 is the current release of Source Serif Pro — same design,
     plus a variable optical-size axis, which matters here because the serif
     runs from 19px (ledes) up to 242px (display). Pro is named next in the
     stack so a locally installed copy still resolves. */
  --serif:"Source Serif 4","Source Serif Pro","Times New Roman",Georgia,serif;

  --d-sans: clamp(40px, 9.1vw, 182px);
  --d-serif: clamp(42px, 12.1vw, 242px);
  --hero: 64px;
  --micro: max(11px, 0.76vw);
  --nav: max(11px, 0.79vw);

  --ease:cubic-bezier(.22,1,.36,1);
}

@media (max-width:820px){ :root{ --pad:18px; --d-sans:clamp(34px,10vw,64px); --d-serif:clamp(34px,9.6vw,64px) } }

html{
  min-height:100%; background:var(--void);
  color-scheme:dark;
  -webkit-text-size-adjust:100%;
  overscroll-behavior-y:none;
}
html.page-light{ background:var(--paper); color-scheme:light }

body{
  margin:0; background:var(--paper); color:var(--ink);
  min-height:100%; min-height:100dvh;
  font-family:var(--sans); font-weight:400;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
  overscroll-behavior-y:none;
}
/* Safari derives its toolbar/overscroll canvas from the root page paint, not
   from whichever full-bleed section happens to be under it. Keep that canvas
   dark on every dark-starting page; all light sections already paint their
   own backgrounds. */
body:not(.is-contact){ background:var(--void) }
h1,h2,h3,p,figure,blockquote{ margin:0 }
a{ color:inherit; text-decoration:none }
::selection{ background:#0d0d0d; color:#fff }

.serif{ font-family:var(--serif); font-weight:400 }

/* ── display type ───────────────────────────────────────── */
.d-sans{
  font-family:var(--sans); font-weight:400;
  font-size:var(--d-sans); line-height:.98;
  letter-spacing:-.035em;
}
.d-serif{
  font-family:var(--serif); font-weight:400;
  font-size:var(--d-serif); line-height:.99;
  letter-spacing:-.012em;
}

/* masked line/word reveal primitives.
   The overflow box needs room on BOTH edges — line-height is below 1 on the
   display faces (.98/.99), so cap-height (S, T...) clips at the top and
   descenders (g, y, Q...) clip at the bottom without this. Padding opens the
   box on each side and the matching negative margin keeps the flowed
   height/position unchanged. */
.ln,.msk{
  display:block; overflow:hidden;
  padding:.16em 0 .18em; margin:-.16em 0 -.18em;
}
.msk{ display:inline-block; vertical-align:top }
/* No will-change here on purpose. These reveals run ONCE, and there is one
   of these spans per word — 72 of them on the home page. Declaring
   will-change in the stylesheet promotes every one to its own compositor
   layer for the life of the page, which pushes Chrome past its layer budget;
   it then starts evicting and re-rasterising layers, and individual words
   flash blank while that happens. main.js promotes them for the length of
   the tween and hands them straight back. */
.ln__i,.msk__i{ display:inline-block }

/* ── placeholders ───────────────────────────────────────── */
.ph{ position:relative; display:block; overflow:hidden; background:var(--ph) }
.ph__fill{
  position:absolute; inset:-8% 0; display:block;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.13), rgba(255,255,255,0) 60%),
    repeating-linear-gradient(135deg, rgba(0,0,0,.016) 0 34px, rgba(0,0,0,0) 34px 68px),
    var(--ph);
  will-change:transform;
}
.ph::after{
  content:attr(data-ph);
  position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  font-size:var(--micro); letter-spacing:.16em; text-transform:uppercase;
  color:rgba(255,255,255,.5); z-index:2; pointer-events:none;
}
.ph__fill--img{
  background:var(--ph) url("https://d1ehi4znk0tdbs.cloudfront.net/moretasks-website-final/img/team-photo.jpg") center/cover no-repeat;
}
.ph--shade::before{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:linear-gradient(to top, rgba(0,0,0,.42), rgba(0,0,0,0) 42%),
             linear-gradient(to bottom, rgba(0,0,0,.28), rgba(0,0,0,0) 26%);
}

/* ── loader ─────────────────────────────────────────────── */
.loader{ display:none }
.js .loader{
  position:fixed; inset:0; z-index:90; background:var(--paper);
  display:flex; align-items:center; justify-content:center; pointer-events:none;
}
.loader__bar{
  width:min(30vw,360px); height:2px; background:var(--ink);
  transform-origin:left center; transform:scaleX(0);
}

/* ── header ─────────────────────────────────────────────── */
.hdr{
  position:fixed; inset:0 0 auto 0; z-index:40;
  display:flex; align-items:flex-start; justify-content:space-between;
  padding:var(--pad);
  /* Always white + mix-blend-mode:difference (kononenkogroup.com's header
     trick): the browser inverts per-pixel against whatever is directly
     behind it — difference(white, black bg) = white, difference(white,
     white bg) = black — so the logo/nav stay legible over any background
     (photo, video, gradient, light or dark section) with no JS section
     tracking needed. Replaces the old per-section .is-light toggle, which
     only ever knew a section's nominal light/dark flag, not what was
     actually painted behind the header at that scroll position. */
  color:#fff; mix-blend-mode:difference;
  transition:opacity .45s var(--ease);
}
/* Always visible now — the header no longer hides near the footer or while
   scrolling down. JS still toggles .is-gone/.is-away at the same triggers as
   before; these are kept as harmless no-ops rather than ripping out that
   logic, so re-enabling the old behaviour later is a one-line revert. */
.hdr.is-gone,
.hdr.is-away{ opacity:1; pointer-events:auto }
.mark{
  display:block; line-height:0; color:inherit;
}
.mark__svg{
  display:block; width:auto; height:clamp(20px,2.3vw,30px);
  color:currentColor;
}
.nav{ font-size:var(--nav); display:flex; gap:1em; align-items:baseline }
.nav__a{ position:relative }
.nav__a.is-on{ text-decoration:underline; text-underline-offset:.22em }
.nav__a::after{
  content:""; position:absolute; left:0; right:0; bottom:-.2em; height:1px;
  background:currentColor; transform:scaleX(0); transform-origin:left;
  transition:transform .4s var(--ease);
}
.nav__a:hover::after{ transform:scaleX(1) }

/* ══════════════════════════ 1 · hero ══════════════════════
   Scroll pulls back from one frame to the whole wall, then the wall washes
   out to white and hands off to the statement below. The section is tall and
   the pin is what you actually see. */
/* 560, not 320: the section now runs two acts — pull back to the wall and wash
   white, then return, travel one tile diagonally and land on it. 320/560 is
   HERO_SPLIT in main.js, which keeps the opening act's on-screen scroll
   distance exactly what it was before the return was added. */
.hero{ position:relative; height:150svh }
.hero__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  background:var(--paper);
}
.hero__grid{
  position:absolute; top:50%; left:50%;
  transform:translate(-50%,-50%);
  transform-origin:50% 50%;
  display:grid;
  /* the gutters ARE this background — white, not the pin showing through */
  background:var(--paper);
  will-change:transform;
  /* columns/rows and the gap are written by main.js so the cell aspect stays
     put across viewports */
}
.hero__cell{
  position:relative; overflow:hidden;
  background:var(--ph);              /* grey placeholder until artwork lands */
  /* No will-change: the cells' opacity was animated back when the wall
     washed out to white, and that move is long gone — the wall now stays on
     screen the whole time and only .hero__grid transforms. The hint was
     still promoting all 50 cells to their own layers for nothing. */
}
.hero__cell video,
.hero__cell img{
  position:absolute; left:0; top:-11%;
  width:100%; height:122%; object-fit:cover; display:block;
}
/* The source film is letterboxed: measured 28px of pure black top and bottom on
   a 360px frame, 7.8% a side, identical in every clip. object-fit:cover on an
   exactly-fitting box still shows them — the element fills, the PICTURE does
   not — so the video has to overscan past its box to crop them. 122%/-11%
   clears it with room to spare. */

.hero__title{
  position:absolute; left:var(--pad); bottom:calc(var(--pad) + .4vw); z-index:7;
  color:#fff; font-size:clamp(28px,7vw,64px); line-height:1.03; letter-spacing:-.022em;
  will-change:opacity;
}
.hero__title .ln__i.serif{ font-size:clamp(20px,5vw,48px) }

/* reduced motion: no pin, no zoom — just the first frame */
.no-motion .hero{ height:100svh }
.no-motion .hero__pin{ position:relative }

/* ══════════════════════ 2 · statement ═════════════════════ */
.stmt__head{ padding-inline:var(--pad) }
.stmt__notes{
  display:grid;
  grid-template-columns:26% 18% 8.5% 18% 1fr;
  margin-top:clamp(22px,2.4vw,44px);
  margin-bottom:clamp(60px,8vw,150px);
}

.stmt__notes p:nth-of-type(1){ grid-column:2 }
.stmt__notes p:nth-of-type(2){ grid-column:4 }

.stmt__notes p{
  font-size:var(--micro); line-height:1.42; color:var(--muted);
}


/* ══════════════════════ 2b · about ═══════════════════════ */
/* ═════════════════════ 2b · statement ═════════════════════
   Opens the page below the hero, running the full measure flush to both
   margins — same width the figures below occupy. */
.statement{
  background:var(--paper);
  padding:clamp(80px,9vw,170px) var(--pad) clamp(70px,8vw,150px);
}
.statement__t{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(19px,2.1vw,42px); line-height:1.12; letter-spacing:-.006em;
}

/* ═══════════════════════ 2b2 · stats ══════════════════════
   Figures run the full measure, flush left with the statement above. Four
   across at desktop — with no label rail taking a third of the row, two
   columns would leave each figure stranded in half a viewport. */
.stats{
  background:var(--paper);
  padding:0 var(--pad) clamp(80px,9vw,170px);
}
.stats__grid{
  display:grid; grid-template-columns:repeat(4,1fr);
  column-gap:clamp(20px,2.4vw,48px);
}
/* Four across needs roughly 240px a column before the figures start colliding
   with their own captions; below that, drop to two and let the rows stack. */
@media (max-width:1100px){
  .stats__grid{ grid-template-columns:repeat(2,1fr) }
}
/* Hairline over each cell, matching .office's rules — the figures read as a
   table of record rather than as four floating cards. */
.stat{
  display:block;
  padding:clamp(14px,1.35vw,28px) 0;
  border-top:1px solid #e6e6e6;
}
.stat__n{
  display:block;
  font-family:var(--sans); font-weight:400;
  font-size:clamp(26px,2.9vw,58px); line-height:1.04; letter-spacing:-.035em;
}
.stat__l{
  display:block; margin-top:.55em;
  font-size:max(11px,.85vw); line-height:1.45; color:#9a9a9a;
}

/* ══════════════════════ offices table ═════════════════════
   The index no longer carries an offices section; these rules now serve only
   the list embedded in about.html's philosophy section, which supplies its
   own container, label, and dark treatment via .offices__list--dark. */
.offices__list{
  position:relative; flex:0 0 47.04%; margin-left:4.1%;
  isolation:isolate;
}
.offices__rows{ display:block }
.office{
  display:grid;
  grid-template-columns:28.7% 29.4% 40.8% 1.1%;
  align-items:baseline;
  padding:clamp(9px,.85vw,18px) 0;
  border-top:1px solid #e6e6e6;
  font-size:max(12px,.85vw); line-height:1.3;
  color:var(--ink);
}
.office:last-child{ border-bottom:1px solid #e6e6e6 }
.office__c,.office__a{ color:#9a9a9a }
.office__x{ justify-self:end; font-size:.92em; opacity:.55 }

/* the sliding card: a black plate that carries its own copy of the rows,
   so the type inverts exactly where the plate covers it */
.offices__mask{
  position:absolute; inset:0 0 auto 0; z-index:2;
  overflow:hidden; background:var(--ink);
  opacity:0; pointer-events:none;
  will-change:transform;
}
.offices__mask .office{
  border-top-color:transparent; color:#fff;
}
.offices__mask .office:last-child{ border-bottom-color:transparent }
.offices__mask .office__c,
.offices__mask .office__a{ color:#c9c9c9 }
.offices__mask .office__x{ opacity:1 }
.offices__rows--inv{ will-change:transform }

/* ═══════════════════ 3 · radial / inversion ═══════════════ */
.radial{ height:300vh; position:relative; background:var(--paper) }
.radial__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  display:grid; place-items:center;
}
/* A centred SQUARE, not a stretched fill — the reference sizes its fan box to
   ~80% of the viewport height and lets the page breathe around it. The
   numbers ride at 1.06x the tip radius, outside the viewBox, so overflow has
   to stay visible. Rotation happens in the path data now, never as a CSS
   transform, so there is nothing to promote. */
.radial__svg{
  position:absolute; left:50%; top:50%;
  width:min(78svh,84vw); height:min(78svh,84vw);
  transform:translate(-50%,-50%);
  overflow:visible;
}
/* Soft haze behind the centre — the spokes converge and read as a hard knot
   without it. backdrop-filter so it blurs whatever the section currently is,
   which matters because this section inverts white -> black mid-scroll. */
.radial__haze{
  position:absolute; left:50%; top:50%;
  width:min(46vw,620px); aspect-ratio:1;
  transform:translate(-50%,-50%);
  border-radius:50%;
  backdrop-filter:blur(26px);
  -webkit-backdrop-filter:blur(26px);
  -webkit-mask-image:radial-gradient(circle at center, #000 0%, #000 34%, transparent 72%);
  mask-image:radial-gradient(circle at center, #000 0%, #000 34%, transparent 72%);
  pointer-events:none; z-index:1;
}
.radial__type{ z-index:2 }
/* stroke width and group opacity match the reference (0.94 / 0.5 on the
   masked group — the group carries the opacity now, not each path).
   Tick font-size is in SVG USER UNITS, so it scales with the box: 13 units in
   a ~1050px box is ~15px on screen. On a phone the box drops to ~345px and the
   same 13 units render at 4.5px — illegible — so the unit size climbs as the
   box shrinks. */
.radial__svg .spoke{ fill:none; stroke:currentColor; stroke-width:.94 }
.radial__svg .tick{ font-family:var(--sans); font-size:13px; letter-spacing:.06em; fill:currentColor }
@media (max-width:820px){
  .radial__svg{ width:min(64svh,84vw); height:min(64svh,84vw) }
  .radial__svg .spoke{ stroke-width:1.6 }
  .radial__svg .tick{ font-size:27px }
  .radial__haze{ width:min(72vw,620px) }
}
.radial__pin{ color:var(--ink) }
/* The two headlines swap by sliding through this window rather than
   cross-fading. Stacked in one grid cell, a fade left both readable at once
   over the mid-grey of the inversion — a double exposure. Clipping instead
   means only one is ever in view. Padding keeps descenders off the clip edge,
   the negative margin cancels it from layout. */
.radial__type{
  position:relative; z-index:2; display:grid; place-items:center;
  overflow:hidden; padding-block:.16em; margin-block:-.16em;
}
.radial__t{
  grid-area:1/1; text-align:center;
  font-size:clamp(30px,4.2vw,80px); line-height:1.06; letter-spacing:-.028em;
  will-change:transform;
}
/* parked below the window until the swap; travel exceeds 100% so the padded
   band is cleared too */
.radial__t--b{ color:#fff; transform:translateY(112%) }

/* ═══════════════════ 3a · TAP (pinned reveal) ═══════════════════
   Each word is CAP + REST; REST sits clipped to width:0 at rest so the row
   reads as the bare acronym "TAP", then main.js scrubs each REST open to
   its measured natural width as the section scrolls. */
.tap{ background:var(--paper); color:var(--ink); height:250vh; position:relative }
.tap__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:clamp(40px,6vw,90px);
}
/* Visible only while the row still reads as the bare acronym — main.js
   fades this out the instant the letters start pulling apart into words. */
.tap__eyebrow{
  display:block; font-family:var(--sans); font-weight:400;
  font-size:clamp(26px,3.2vw,48px); color:var(--muted); text-align:center;
}
/* two nested layers so the one-off entrance zoom (main.js, on .tap__stage)
   and the continuous scroll-scrubbed "shrink to keep fitting" (main.js, on
   .tap__row, as the letters grow into full words) never fight over the
   same transform */
.tap__stage{ display:flex; align-items:center; justify-content:center; width:100% }
.tap__row{
  display:flex; align-items:baseline; justify-content:center;
  padding:0 var(--pad); gap:clamp(22px,5vw,84px);
  transform-origin:50% 50%;
}
.tap__word{ display:inline-flex; align-items:baseline }
.tap__cap,.tap__rest{
  font-family:var(--sans); font-weight:500;
  font-size:clamp(120px,28vw,460px); line-height:1; letter-spacing:-.02em;
  white-space:nowrap;
}
.tap__rest{ display:inline-block; overflow:hidden; width:0; will-change:width }

@media (max-width:820px){
  /* Exactly the desktop behaviour, just smaller: ONE horizontal row that
     scales down as the letters open into words. It used to stack into a
     column here, which broke the whole idea twice over — "TAP" only reads
     as an acronym while the three letters share a line, and a column has no
     line to keep them on, so the scale-to-fit trick the expansion depends
     on had to be switched off with it. */
  /* Desktop's 250vh scroll-through is tuned for three words sharing one
     line at display size; at the smaller mobile type size the same letters
     finish expanding in far less scroll distance, so the full 250vh just
     sat there as dead space once the animation was already done. */
  /* Kept in proportion with .tap__pin below: the pin only fills the top
     part of the viewport now, and the parent's extra height is what shows
     as dead white space beneath a short sticky pin for the whole scroll
     range it's pinned over — the taller this is relative to the pin, the
     longer that gap sits on screen before the section finally releases. */
  .tap{ height:70vh }
  /* Sticky doesn't require filling the full viewport — it just needs to
     stick to the top while .tap scrolls past underneath it. The desktop
     100svh reads as a deliberate full-screen "slide"; at the smaller
     mobile type size the same full-screen box just left the words sitting
     in a lot of dead space above and below them. */
  .tap__pin{ height:38vh; gap:clamp(16px,5vw,32px) }
  /* Redundant centering alongside .tap__stage's justify-content:center —
     the row's own width is being rewritten every frame by the letter-width
     scrub, and margin:auto on a flex item re-centers it independently of
     whatever the parent's justify-content last resolved to, so it can't
     drift off-centre as that width changes under it. */
  .tap__row{ margin-inline:auto }
  .tap__eyebrow{
    font-size:clamp(15px,4.6vw,26px);
    padding:0 var(--pad);          /* it ran off the right edge without this */
  }
  .tap__row{ gap:clamp(10px,3.4vw,22px) }
  .tap__cap,.tap__rest{ font-size:clamp(56px,26vw,120px) }
}
.no-motion .tap{ height:auto }
.no-motion .tap__pin{ position:relative; height:auto; padding:22vh 0 }
.no-motion .tap__rest{ width:auto }

/* ═════════════════════════ 3b · values (pinned) ═══════════════════════
   main.js crossfades .value__media/.value__copy pairs and replays the
   incoming headline's mask reveal at each of the two transitions.

   400vh, not 300: the pin eats one viewport, so the scroll-through distance
   is height - 100vh. At 300vh that left only 200vh for three stages, and the
   third one's turn began exactly as the pin released — Productivity was still
   arriving while the section scrolled away, so it never sat centred the way
   the first two do. 400vh gives a full 100vh hold per stage, third included. */
.value{ position:relative; height:220vh; color:var(--ink-i) }
.value__pin{ position:sticky; top:0; height:100svh; overflow:hidden }
.value__media{ position:absolute; inset:0 }
.value__media img{ width:100%; height:100%; object-fit:cover; display:block }
.value__scrim{
  position:absolute; inset:0; z-index:1;
  background:linear-gradient(180deg, rgba(0,0,0,.15), rgba(0,0,0,.5) 60%, rgba(0,0,0,.65));
}
.value__copy{
  position:absolute; inset:0; z-index:2; text-align:center;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:clamp(20px,2.6vw,35px);
  width:min(84vw,1148px); margin-inline:auto; padding:0 var(--pad);
}
.value__t{
  font-family:var(--sans); font-weight:500; color:#fff;
  font-size:clamp(48px,10.6vw,182px); line-height:1.05; letter-spacing:-.02em;
  margin:0;
}
.value__d{
  font-family:var(--sans); font-weight:400; color:#fff;
  font-size:clamp(17px,1.75vw,30px); line-height:1.27;
  max-width:52ch; margin:0;
}

@media (max-width:820px){
  /* Same pinned, three-stage crossfade as desktop. Only the crop and type
     scale change for the portrait viewport. */
  .value{ height:220vh }
  .value__pin{ position:sticky; top:0; height:100svh; overflow:hidden; display:block }
  .value__media{ position:absolute; inset:0; min-height:0 }
  .value__media::after{ content:none }
  .value__media img{ object-position:center center }
  .value__media:nth-child(1) img{ object-position:48% center }
  .value__media:nth-child(2) img{ object-position:51% center }
  .value__media:nth-child(3) img{ object-position:24% center }
  .value__scrim{ display:block }
  .value__copy{
    position:absolute; inset:0;
    width:min(92vw,560px); margin-inline:auto;
    padding:0 var(--pad); gap:clamp(16px,4.5vw,24px);
  }
  .value__t{
    font-size:clamp(38px,11.5vw,56px);
    line-height:1; white-space:nowrap;
  }
  .value__d{ font-size:clamp(16px,4.25vw,19px); line-height:1.35; max-width:34ch }
}

/* ═══════════ 4-5 · people reveal (placeholder) ═══════════
   Hero-style image reveal, ported from a reveal template as a stand-in for
   the People & Process content — swap the images for the real thing when
   it's ready. Plays once on scroll via a dedicated ScrollTrigger (see
   main.js §10), since the section sits mid-page rather than on page load. */
.people-reveal{
  position:relative; height:100svh; overflow:hidden;
  background:var(--paper); color:var(--ink);
}
.people-reveal__img{
  position:absolute; inset:0;
  overflow:hidden; border-radius:.5rem;
  transform-origin:center center; will-change:transform;
}
/* Stacked above the other four so, once it grows to cover the section, the
   departing side cards read as sliding away in front of it rather than
   racing an equal-stacked hero to fill the frame. */
.people-reveal__img--hero{ z-index:1 }
.people-reveal__img picture{ display:block; width:100%; height:100%; }
.people-reveal__img img{
  display:block; width:100%; height:100%; object-fit:cover;
}
/* The mobile hero photo is a square headshot; centred cover crops it against
   a full-bleed 100svh section, so the composed frame catches her collar, not
   her face. Anchoring near the top of the frame keeps her face in view. */
.people-reveal__img--hero img{ object-position:50% 18%; }
/* The desktop-only photo (see the <picture> source in index.html) is a wide
   candid already framed with headroom, so cover only trims top/bottom —
   default centring already keeps her face in frame. */
@media (min-width:821px){
  .people-reveal__img--hero img{ object-position:50% 25%; }
}
/* Faded in by main.js §10 once the hero image settles — opacity:0 here is
   the resting state, not a flash-of-unstyled-content guard. */
.people-reveal__cap{
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  padding:clamp(24px,4vw,58px) var(--pad);
  display:flex; flex-direction:column; gap:.3em;
  color:#fff; opacity:0; pointer-events:none;
  background:linear-gradient(to top, rgba(0,0,0,.88) 15%, rgba(0,0,0,0) 92%);
}
.people-reveal__quote{
  max-width:44ch; margin:0 0 clamp(14px,1.6vw,22px);
  font-family:var(--serif); font-weight:400;
  font-size:clamp(19px,2vw,30px); line-height:1.32; letter-spacing:-.006em;
}
.people-reveal__name{
  font-family:var(--sans); font-weight:400; font-size:clamp(18px,1.5vw,24px);
  letter-spacing:-.02em;
}
.people-reveal__role{
  font-size:var(--micro); color:rgba(255,255,255,.75);
}
.people-reveal__nav{
  display:flex; align-items:center; gap:14px;
  margin-top:clamp(20px,2.6vw,36px);
}
.people-reveal__arrow{
  width:38px; height:38px; border-radius:50%; flex-shrink:0;
  border:1px solid rgba(255,255,255,.4); background:none; color:#fff;
  display:grid; place-items:center; cursor:pointer;
  transition:background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.people-reveal__arrow:hover{ background:#fff; color:#000; border-color:#fff }
.people-reveal__arrow svg{ display:block }
.people-reveal__dots{ display:flex; gap:8px }
.people-reveal__dot{
  width:7px; height:7px; border-radius:50%; padding:0; border:none;
  background:rgba(255,255,255,.4); cursor:pointer;
  transition:background .25s var(--ease), transform .25s var(--ease);
}
.people-reveal__dot.is-on{ background:#fff; transform:scale(1.3) }

.no-motion .people-reveal__img{ display:none }
.no-motion .people-reveal__img--hero{
  display:block; position:relative; inset:auto;
  width:100%; height:100%; border-radius:0;
}
.no-motion .people-reveal__cap{ opacity:1; pointer-events:auto }

/* ═════════════════ 6c · office / amenities ═════════════════
   A horizontal filmstrip driven by vertical scroll, over a static intro
   screen. The intro (.aslide-intro) fills the pinned viewport and never
   moves: black copy panel left, full-bleed photo right — that is the first
   screen, before any scrolling. The strip (.aslider__track) is ONE flex row
   parked just off the right edge, which JS translates leftwards; because it
   carries its own white background it slides in across the intro photo,
   covering it from the right, and then keeps going. No per-slide show/hide
   and no crossfade anywhere: the strip just moves, and the viewport is a
   window onto it.

   Per slide the three pieces are separate track columns in reading order
   (heading, image, caption) rather than a copy block beside the image. That
   is what gives the reference its rhythm — a heading arriving top-left, its
   image filling the middle, its caption trailing along the bottom while the
   NEXT heading is already entering from the right. */
.amenities{ position:relative; background:var(--void) }

/* Height is overwritten by JS to (viewport + one viewport of lead-in +
   horizontal distance) so the strip travels 1:1 with the wheel; the calc is
   the pre-JS fallback and keeps the page from jumping if the script never
   runs. */
.aslider{ position:relative; height:calc(8 * 100vh) }
.aslider__pin{ position:sticky; top:0; height:100svh; overflow:hidden; background:var(--paper) }

/* The static first screen. Sits under the strip, so the strip's white
   background is what wipes it away — the intro itself never moves. */
.aslide-intro{ position:absolute; inset:0; z-index:1; display:flex; align-items:stretch }
.aslide-intro__copy{
  flex:0 0 auto; width:min(49vw,760px);
  background:var(--void); color:var(--ink-i);
  display:flex; flex-direction:column; justify-content:center;
  gap:clamp(18px,2.4vw,32px);
  padding:0 var(--pad);
}
/* Takes whatever the copy panel leaves, and bleeds to the top, bottom and
   right edges of the viewport. */
.aslide-intro__media{ position:relative; flex:1 1 auto; min-width:0; overflow:hidden; background:#111 }
.aslide-intro__media img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; display:block;
}

/* z-index above the intro, and its own opaque background: together those are
   what make the strip read as sliding in over the intro photo rather than
   appearing beside it. The left padding keeps the first heading off the
   white's leading edge as it arrives. */
.aslider__track{
  position:absolute; inset:0 auto 0 0; z-index:2; height:100%;
  /* Roughly double the slide's own internal gap: the strip has to read as a
     sequence of separate slides, so the space between one slide's caption
     and the NEXT slide's image must clearly beat the space between a slide's
     own text column and its image. At parity the two gaps were
     indistinguishable and the next photo looked like it belonged to the
     caption beside it. */
  display:flex; align-items:stretch; gap:clamp(88px,10vw,200px);
  padding-left:clamp(28px,3vw,60px);
  /* Matches main.js's trailing gutter (A_TAIL) — as PADDING, not just extra
     scroll travel, so the track's own white background still covers that
     gutter. It used to be travel-only: the strip's box (background included)
     is only as wide as its content, so scrolling A_TAIL px further than that
     ran the box itself off-screen before the scroll-through finished,
     exposing the never-moving .aslide-intro layer underneath — its black
     panel/photo flashing back in right at the end, reading as the slider
     "getting cut off". */
  padding-right:clamp(60px,8vw,120px);
  background:var(--paper);
  will-change:transform;
}
.amenities__t{
  text-align:left; letter-spacing:-.02em; margin:0; max-width:18ch;
  font-family:var(--sans); font-weight:400;
  font-size:clamp(28px,3.6vw,52px); line-height:1.12;
}
.amenities__d{
  font-size:clamp(15px,1.35vw,20px); line-height:1.5; color:var(--muted-i);
  max-width:40ch; margin:0; text-align:left;
}

/* Symmetric vertical padding: it is the slide's own inset that puts the
   image's top and bottom edges where they are, and the same box is what
   flex-start/flex-end align the heading and caption against — so heading
   top, image top, caption bottom and image bottom all line up. */
.aslide{
  flex:0 0 auto; color:var(--ink);
  display:flex; align-items:stretch; gap:clamp(40px,5vw,96px);
  padding:clamp(48px,7.6vh,110px) 0;
}
/* Deliberately narrow measure: the reference wraps even a short heading to
   two or more lines, which is what keeps the heading reading as a column of
   the strip rather than a banner running into the image. The top margin
   drops it below the image's top edge (and clear of the fixed header).
   Stretched to the slide's full content height with space-between, so the
   heading sits at the top of the column and the caption drops to the bottom
   — heading top and caption bottom then line up with the image's own top
   and bottom edges, which is the rhythm the mock has. */
.aslide__text{
  flex:0 0 auto; align-self:stretch; width:min(26vw,380px);
  margin:clamp(10px,4.4vh,60px) 0 0;
  display:flex; flex-direction:column; justify-content:space-between;
  gap:clamp(18px,2.4vw,32px);
}
.aslide__t{
  margin:0;
  font-family:var(--sans); font-weight:400; color:var(--ink);
  font-size:clamp(28px,3.6vw,54px); line-height:1.14; letter-spacing:-.015em;
}
/* .aslide__cap is a plain block inside .aslide__text, held at the bottom of
   that column by the space-between above — full body size, ink, sentence
   case, meant to be read rather than the tracked-out micro label the card
   sections use (see .aslide__d/.aslide__source below). */
.aslide__cap{ margin:0 }
.aslide__d{
  margin:0 0 .9em; color:var(--ink);
  font-size:clamp(15px,1.5vw,24px); line-height:1.42;
}
.aslide__d:last-child{ margin-bottom:0 }
.aslide__source{
  margin:0; color:var(--muted);
  font-size:clamp(13px,1.1vw,17px); line-height:1.42;
}
.aslide__source strong{ color:var(--ink); font-weight:600 }
.aslide__media{
  position:relative; flex:0 0 auto; align-self:stretch;
  width:min(55vw,860px);
  overflow:hidden; border-radius:2px;
  background:#ececec;
}
/* Oversized inside its frame so the internal pan (see main.js) has room to
   move the picture without ever exposing an edge: 12% of the frame's width
   of slack on each side against a pan that reaches 10.5%, so there is ~1.5%
   of margin left over for subpixel rounding at the extremes. */
.aslide__media img{
  position:absolute; left:-12%; top:-6%; width:124%; height:112%;
  object-fit:cover; display:block; will-change:transform;
  /* Which part of the photo survives the crop. The frames go portrait on a
     tall viewport while these photos are landscape, so cover throws away a
     lot of width — and dead centre is not always where the subject is. Per
     slide override with --focus on .aslide__media. Percentages, so the
     shift scales with however much overflow there actually is. */
  object-position:var(--focus,50%) var(--focus-y,50%);
}
@media (max-width:820px){
  /* Keep the desktop filmstrip choreography on phones. The intro becomes a
     two-row viewport, while the white strip still wipes across it from the
     right and continues horizontally through every amenity. */
  .aslider{ height:calc(8 * 100vh) }
  .aslider__pin{ position:sticky; top:0; height:100dvh; overflow:hidden }
  .aslider__track{
    position:absolute; inset:0 auto 0 0; height:100%;
    flex-direction:row; gap:clamp(56px,16vw,96px);
    padding-left:var(--pad); padding-right:clamp(42px,14vw,72px);
  }
  .aslide-intro{ position:absolute; inset:0; flex-direction:column }
  .aslide-intro__copy{
    flex:0 0 56%; width:100%;
    padding:calc(64px + env(safe-area-inset-top)) var(--pad) clamp(26px,7vw,42px);
    gap:clamp(16px,4vw,22px);
  }
  .aslide-intro__media{ flex:1 1 auto; height:auto; min-height:0; aspect-ratio:auto }
  .aslide-intro__media img{ object-position:center 42% }
  .amenities__t{ max-width:none }
  .aslide{
    flex-direction:row; align-items:stretch;
    padding:calc(68px + env(safe-area-inset-top)) 0 max(54px,env(safe-area-inset-bottom));
    gap:clamp(26px,8vw,42px);
  }
  .aslide__text{
    width:min(76vw,320px); margin:clamp(10px,3vh,24px) 0 0;
    gap:clamp(14px,3.4vw,22px);
  }
  .aslide__t{ font-size:clamp(32px,10vw,44px) }
  .aslide__d{ font-size:clamp(16px,4.3vw,19px) }
  .aslide__source{ font-size:clamp(13px,3.6vw,15px) }
  .aslide__media{ width:min(78vw,340px); aspect-ratio:auto; align-self:stretch }
}

/* ═════════════════ 6d · scroll-activated text ═════════════════
   Adapted from Codegrid's "scroll-activated text blocks": three short
   statements sit in fixed columns; as the pinned section scrolls, each
   column's words mask out while the next column's words mask in — so the
   three ideas play in sequence rather than all at once. A velocity-reactive
   image marquee rides along the bottom of the same pin. */
.scrolltext{ background:var(--void); color:var(--ink-i); height:400vh; position:relative }
.scrolltext__pin{ position:sticky; top:0; height:100svh; overflow:hidden }

/* The title is placed absolutely on its own on the home page. Where it has
   a lede under it (why-us), the pair is wrapped so the two travel together
   and the lede cannot drift over the columns. */
.scrolltext__head{
  position:absolute; left:var(--pad); top:clamp(28px,4vw,56px); z-index:1;
  max-width:min(70vw,780px);
}
.scrolltext__title{
  position:absolute; left:var(--pad); top:clamp(28px,4vw,56px); z-index:1;
  max-width:min(70vw,780px); margin:0;
  font-family:var(--sans); font-weight:400;
  font-size:clamp(28px,3.8vw,56px); line-height:1.1; letter-spacing:-.01em;
}
/* inside the wrapper it is a normal block again */
.scrolltext__head .scrolltext__title{
  position:relative; left:auto; top:auto; max-width:none;
}
.scrolltext__lede{
  margin:.5em 0 0;
  font-family:var(--sans); font-weight:400; color:var(--muted-i);
  font-size:clamp(14px,1.35vw,20px); line-height:1.4;
}
.scrolltext__indicator{
  position:absolute; width:min(160px,14vw); height:1px; z-index:1;
  top:clamp(30px,4.3vw,58px); right:var(--pad);
  background:#2f2f2f;
}
.scrolltext__indicator::after{
  content:''; position:absolute; inset:0;
  background:#fff; transform-origin:left; transform:scaleX(var(--progress,0));
  will-change:transform;
}

.scrolltext__copy{
  position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:100%; padding:0 var(--pad);
  display:flex; gap:clamp(18px,2.6vw,40px);
}
.scrolltext__block{ flex:1 }
/* The step's heading: sans and a size up from the serif body under it, so
   the two read as heading + paragraph rather than one bolded sentence at
   the top of a block. */
.scrolltext__block .scrolltext__lead{
  font-family:var(--sans); font-weight:500; color:var(--ink-i);
  font-size:clamp(21px,2.4vw,36px); line-height:1.15; letter-spacing:-.015em;
  margin-bottom:.6em;
}
.scrolltext__block p{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(17px,1.7vw,26px); line-height:1.34; letter-spacing:-.006em;
  margin:0;
}
.scrolltext__block p .word{ will-change:transform }

.scrolltext__marquee{
  position:absolute; left:0; bottom:clamp(20px,2.8vw,36px); width:100%;
  height:clamp(130px,16vw,230px); overflow:hidden;
  display:flex; align-items:center;
}
.scrolltext__track{ display:flex; gap:14px; will-change:transform }
.scrolltext__item{
  flex:none; width:clamp(200px,22vw,320px); height:100%;
  border-radius:2px; overflow:hidden; background:var(--ph-dark);
}
.scrolltext__item img{ width:100%; height:100%; object-fit:cover; display:block }

/* ── the marquee-less variant (why-us) ────────────────────
   With no image strip at the bottom, the default composition pools its
   space in the two worst places: the heading is absolutely pinned to the
   top edge (so it sits under the fixed header with nothing above it) and
   the columns are centred on their own (so a tall viewport leaves a dead
   band beneath them). Here the two are laid out as ONE centred group, which
   gives the heading air above it and takes the slack out of the bottom.

   Scoped to the modifier rather than changed on .scrolltext itself: on the
   home page the marquee is absolutely positioned along the bottom, and a
   taller centred group would run into it. */
.scrolltext--plain .scrolltext__pin{
  display:flex; flex-direction:column; justify-content:flex-start;
  padding:clamp(72px,9vh,110px) var(--pad) clamp(36px,5vh,64px);
}
.scrolltext--plain .scrolltext__head,
.scrolltext--plain .scrolltext__title{
  position:relative; left:auto; top:auto;
}
/* The heading stays at the TOP of the pin — centring the pair together sent
   it down to ~40% of the viewport, which read as the section starting late.
   margin-block:auto centres only the COLUMNS in whatever is left below the
   heading, so the heading keeps its place and the slack is split rather than
   all falling under the columns. */
.scrolltext--plain .scrolltext__copy{
  position:relative; left:auto; top:auto; transform:none;
  width:auto; padding:0;
  margin-block:auto;
}

/* static fallback (phone width, or reduced-motion): JS skips the pin and
   the word-mask entirely, so the track never gets a transform — let it
   scroll natively instead of clipping the later images away */
@media (max-width:820px){
  .scrolltext{ height:auto }
  .scrolltext__pin{ position:relative; height:auto; padding:100px 0 40px; overflow:visible }
  /* Was left position:absolute while its siblings above were un-stacked
     back into normal flow — it stayed pinned to the top-left corner of the
     section, floating over whichever paragraph now flowed underneath it. */
  .scrolltext__title{ position:relative; left:auto; top:auto; max-width:100%; margin:0 0 28px; padding:0 var(--pad) }
  .scrolltext__head{ position:relative; left:auto; top:auto; max-width:100%; margin:0 0 28px; padding:0 var(--pad) }
  .scrolltext__head .scrolltext__title{ margin:0; padding:0 }
  .scrolltext__copy{ position:relative; top:auto; transform:none; flex-direction:column; gap:28px }
  .scrolltext__marquee{ position:relative; bottom:auto; margin-top:36px; overflow-x:auto; scrollbar-width:none }
  .scrolltext__marquee::-webkit-scrollbar{ display:none }
}
.no-motion .scrolltext{ height:auto }
.no-motion .scrolltext__pin{ position:relative; height:auto; padding:100px 0 40px; overflow:visible }
.no-motion .scrolltext__title{ position:relative; left:auto; top:auto; max-width:100%; margin:0 0 28px }
.no-motion .scrolltext__head{ position:relative; left:auto; top:auto; max-width:100%; margin:0 0 28px }
.no-motion .scrolltext__copy{ position:relative; top:auto; transform:none; flex-direction:column; gap:28px }
.no-motion .scrolltext__marquee{ position:relative; bottom:auto; margin-top:36px; overflow-x:auto; scrollbar-width:none }
.no-motion .scrolltext__marquee::-webkit-scrollbar{ display:none }

/* ═══════════════════════ 6 · brands ══════════════════════ */
.brands{ background:var(--void); color:var(--ink-i); height:200vh; position:relative }
.brands__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  display:grid; place-items:center;
}
.brands__ring{
  position:absolute; inset:0;            /* fills the pin, so its LAYOUT box
                                            gives JS a resolvable size to read.
                                            No transform of its own — GSAP owns
                                            the scroll scale on this element. */
  will-change:transform;
}
/* The ring is an ELLIPSE, not a circle, and it is taller than it is wide.
   Measured off the reference: horizontal semi-axis 508px, vertical 563.5px in
   a 1394px viewport — B/A = 1.1085, A = 0.3646vw. That ratio is what reads as
   a ring lying back in 3D rather than a flat hoop. The vh term keeps it from
   running off a short window. */

.chip{
  position:absolute; left:50%; top:50%;
  will-change:transform,opacity;
  /* JS writes width/height/transform/opacity/z-index every frame */
}
.chip__i{
  display:block; width:100%; height:100%;
  border-radius:50%; overflow:hidden;
  background:#f8f8f8;                    /* the reference chip is a near-white disc */
  transform:translateZ(0);
  backface-visibility:hidden;
}
.chip__i img{ display:block; width:100%; height:100%; object-fit:cover }

/* Reference heading: 127px at a 1394px viewport (0.0911vw), leading 0.8167,
   block 804px wide = 0.577vw. The block has to stay narrower than the ring's
   1016px horizontal span or the words collide with the chips instead of
   sitting in the hole. z-index 2 puts it between the back and front chips. */
.brands__t{
  position:relative; z-index:2; text-align:center;
  width:min(57.7vw, 900px); max-width:none;
  margin-inline:auto; padding-inline:0;
  /* Reference sets 127px in an 804px block — but that block is 0.79 of the
     ring's 1016px span, and THAT proportion is what keeps the words inside the
     hole. Source Serif is wider than the reference face, so holding 0.577vw
     and trimming the type 6.7% (0.0911 -> 0.085vw) lands the same four lines
     inside the same proportion, rather than widening into the chips. */
  /* width and font-size are written by layoutBrands() from the ring's own A,
     so the words always sit inside the hole; these are the pre-JS fallback */
  font-size:clamp(28px, 8.5vw, 170px);
  line-height:.8167; letter-spacing:-.018em;
}

/* ═══════════════════════ 7 · footer ══════════════════════ */
.foot{ background:var(--void); color:var(--ink-i); height:170vh; position:relative }
.foot__inner{
  position:sticky; top:0; height:100svh;
  display:flex; flex-direction:column;
  /* Links at the TOP again — the header hides itself when the footer arrives,
     so there is nothing left to clear. The wordmark takes margin-top:auto, so
     the spare height sits between the links and the mark, the way the
     reference composes it (their columns sit 137px into a 1354px frame ≈ 10vh). */
  padding:clamp(44px,10vh,140px) var(--pad) clamp(12px,1.6vh,22px);
  overflow:hidden;
}
.foot__cols{
  display:flex; align-items:flex-start; gap:2.4%;
  font-size:var(--nav);
}
.foot__col{ flex:1 1 0; display:flex }
/* The label column is a FIXED width, not a share of the column: the reference
   starts every value exactly 107px right of its label at vw 1639 (6.53vw),
   which is what makes the four pairs read as aligned. The old 44% reservation
   scaled with the column and left each value stranded far from its label. */
.foot__k{ flex:0 0 clamp(84px,6.53vw,110px); color:var(--muted-i) }
.foot__v{ flex:1 1 0; display:flex; flex-direction:column; line-height:1.3 }
.foot__v a{ position:relative; width:fit-content }
.foot__v a.is-on{ text-decoration:underline; text-underline-offset:.22em }
.foot__v a:hover{ color:#b9b9b9 }
.foot__v p{ margin:0 }

/* flex:0 0 auto so the wrap hugs the wordmark rather than absorbing the spare
   height — space-between owns that gap now, so no margin is needed here. */
.foot__markwrap{
  flex:0 0 auto; display:flex; align-items:flex-end;
  min-height:0;
  /* margin-top:auto is what pushes the mark (and the rights line after it) to
     the bottom and pools all the spare height above, between links and mark. */
  margin-top:auto;
  /* No negative margin and no centring. It used to cancel .foot__inner's
     padding to run edge to edge, but the SVG stops growing at its intrinsic
     2298px, so past that width justify-content:center left it floating with
     matching slack each side — 131px a side at 2560, which read as a stray
     indent rather than a full-bleed mark. It now starts on the same --pad
     margin as the header logo and the footer columns. */
}
/* flex:1 + min-width:0 is what makes the mark actually take the width it is
   given; content-sized, it capped at the SVG's intrinsic width. */
.foot__mark{
  display:block; flex:1 1 auto; min-width:0;
}
/* Full-bleed width at the bottom of the frame, in currentColor — the same
   white mark the header wears, as inline SVG so it takes the footer's ink. */
.foot__mark__svg{
  display:block; width:100%; height:auto; color:currentColor;
}

/* Tagline sits between the wordmark and the rights line, centered to match
   the mark above it. */
/* The row under the wordmark. The tagline keeps the left margin the mark and
   the columns share; the rights line is pushed to the opposite end so it
   sits under the wordmark's final "s". Baseline-aligned, so the two read as
   one line rather than two blocks that happen to be side by side. */
.foot__base{
  flex:0 0 auto;
  display:flex; align-items:baseline; justify-content:space-between;
  gap:clamp(16px,3vw,48px);
  padding-top:clamp(10px,1.6vh,20px);
}
/* Serif, at one size for both — the sans at --nav made the rights line read
   as small print bolted onto a display line. */
.foot__tagline,
.foot__rights{
  margin:0; flex:0 1 auto;
  font-family:var(--serif); font-weight:400; color:var(--muted-i);
  font-size:clamp(20px,2vw,30px); line-height:1.2;
}
.foot__tagline{ text-align:left }
.foot__rights{ text-align:right; white-space:nowrap }


@media (max-width:640px){
  /* Two 20px serif lines cannot share a row this narrow, so they stack and
     both hang off the left margin. */
  .foot__base{ flex-direction:column; align-items:flex-start; gap:.25em }
  .foot__rights{ text-align:left }
}

/* ══════════════════════ ABOUT PAGE ══════════════════════ */
.is-about{ background:var(--void); color:var(--ink-i) }

/* 1 · hero */
.ahero{ position:relative; height:100svh; overflow:hidden }
.ahero__media{ position:absolute; inset:0; background:#4a4a4a }
/* The photo pans vertically inside this frame as the section scrolls — the
   internal parallax is driven by data-parallax on the fill (see "6 ·
   parallax" in main.js), and .ph clips it.

   The shared .ph__fill bleeds 8% a side, which is all the default drift
   needs; this one travels further than that, so without a deeper bleed the
   frame's own edge would swing into view at the extremes. 16% of slack
   against a pan that reaches 13.5% of the frame leaves ~2.5% spare for
   subpixel rounding. */
.ahero .ph__fill{ inset:-16% 0 }
.ahero__t{
  position:absolute; left:var(--pad); bottom:calc(var(--pad) + .4vw); z-index:3;
  max-width:min(90vw,1100px);
  font-family:var(--sans); font-weight:400; color:#fff;
  font-size:64px; line-height:1.03; letter-spacing:-.022em;
}

/* 2 · philosophy + offices */
.phil{
  background:var(--void);
  display:flex; align-items:flex-start;
  padding:clamp(80px,11vw,200px) var(--pad) clamp(40px,5vw,90px);
}
.phil__k{
  flex:0 0 45%;
  font-family:var(--serif); font-size:max(12px,1.15vw); line-height:1.35;
  padding-top:clamp(50px,7vw,130px);
}
.phil__body{ flex:1 1 0; min-width:0 }
.phil__lede{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(17px,1.6vw,26px); line-height:1.3; letter-spacing:-.006em;
  margin:0 0 1.1em;
}
.phil__lede:last-of-type{ margin-bottom:0 }

.offices__list--dark{ flex:none; margin-left:0; width:90% }
.offices__list--dark .office{ border-top-color:#2a2a2a; color:var(--ink-i) }
.offices__list--dark .office:last-child{ border-bottom-color:#2a2a2a }
.offices__list--dark .office__c,
.offices__list--dark .office__a{ color:#7d7d7d }
/* the plate inverts the other way on a dark page */
.offices__list--dark .offices__mask{ background:#fff }
.offices__list--dark .offices__mask .office{ color:var(--ink) }
.offices__list--dark .offices__mask .office__c,
.offices__list--dark .offices__mask .office__a{ color:#5e5e5e }

/* 3 · the team */
.mates{ background:var(--void); padding-bottom:clamp(80px,10vw,190px) }
.mates__head{ padding:clamp(70px,9vw,170px) var(--pad) clamp(46px,5.5vw,105px) }
.mates__t{
  text-align:center;
  font-size:clamp(44px,7.4vw,148px); line-height:.98; letter-spacing:-.035em;
}
.mates__notes{
  margin-top:clamp(26px,3vw,56px);
}
.mates__notes p{
  font-size:clamp(15px,1.3vw,20px); line-height:1.5; color:var(--muted-i); text-align:center;
  max-width:52ch; margin-inline:auto;
}
.mates__grid{
  display:grid; grid-template-columns:repeat(4,1fr);
  gap:clamp(40px,4.4vw,84px) clamp(8px,.9vw,18px);
  padding-inline:var(--pad);
}
.mate{ display:block }
/* the row is staggered, as in the reference */
.mate--0{ margin-top:0 }
.mate--1{ margin-top:calc(3.2vw) }
.mate--2{ margin-top:calc(6.4vw) }
.mate--3{ margin-top:calc(1.6vw) }
.mate__ph{
  display:block; position:relative; overflow:hidden;
  aspect-ratio:4/5; background:#4a4a4a;
}
.mate__ph img{ display:block; width:100%; height:100%; object-fit:cover }
.mate__cap{
  display:flex; justify-content:space-between; gap:8px;
  margin-top:calc(10px + .5vw);
  font-size:var(--micro); line-height:1.3;
}
.mate__cap span:last-child{ color:var(--muted-i) }

/* 4 · founder */
.founder{
  background:var(--void); color:var(--ink-i);
  padding:clamp(30px,3.5vw,60px) var(--pad) clamp(80px,10vw,190px);
}
.founder__head{ margin-bottom:clamp(50px,6vw,100px) }
.founder__head .mates__t{ text-align:left }
.founder__row{ display:flex; align-items:flex-start }
.founder__ph{ flex:0 0 23.5%; margin:0 }
.founder__q{ flex:1; margin:0 0 0 8.9%; padding-top:.2em }
.founder__quote{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(19px,2.1vw,42px); line-height:1.12; letter-spacing:-.006em;
}
.founder__cite{
  justify-content:flex-start; gap:.6em; margin-top:clamp(18px,2vw,34px);
  font-family:var(--sans); font-size:var(--micro);
}
.founder__bio{
  margin:clamp(18px,2vw,30px) 0 0;
  font-family:var(--sans); font-weight:400; color:var(--muted-i);
  font-size:clamp(16px,1.5vw,22px); line-height:1.55;
}

@media (max-width:820px){
  .ahero__t{ font-size:clamp(24px,7vw,40px) }
  .phil{ flex-direction:column; gap:clamp(30px,6vw,60px) }
  .phil__k{ flex:0 0 auto; padding-top:0 }
  .mates__notes{ display:flex; flex-direction:column; gap:18px }
  .mates__notes p{ text-align:left }
  .mates__grid{ grid-template-columns:repeat(2,1fr) }
  .mate--1,.mate--2,.mate--3{ margin-top:0 }
  /* Name/designation stacked, not side by side — at two-up card width the
     space-between row squeezed the designation into wrapping awkwardly
     next to (or under) the name instead of reading as its own line. */
  .mate__cap{ flex-direction:column; gap:.2em }
  .founder__row{ flex-direction:column; gap:26px }
  /* Full-width and landscape instead of the desktop column's narrow
     portrait crop, which on mobile just left the rest of the row's width
     as dead black space beside it. */
  .founder__ph{ flex:0 0 auto; width:100%; max-width:none }
  .founder__ph .mate__ph{ aspect-ratio:16/12 }
  /* Default center-crop split the loss evenly top/bottom, and at this much
     wider aspect ratio that crops into his hair. Biasing toward the top of
     the source frame keeps the headroom and takes the extra crop out of
     the shirt/chest below instead. */
  .founder__ph .mate__ph img{ object-position:center 28% }
  .founder__q{ margin-left:0 }
}

/* ══════════════════════ responsive ══════════════════════ */
@media (max-width:820px){

  .stats__grid{ grid-template-columns:1fr }

  /* Values keeps the desktop pinned crossfade on mobile. Its extra height is
     the scroll runway for the two stage changes and the final hold. */
  .value{ height:220vh }

  .offices__list{ flex:1 1 auto; width:100%; margin-left:0 }
  .office{ grid-template-columns:1fr auto; row-gap:3px; padding-block:14px }
  .office__n{ grid-area:1 / 1 }
  .office__x{ grid-area:1 / 2 }
  .office__c{ grid-area:2 / 1 }
  .office__a{ grid-area:3 / 1 }
  .offices__mask{ display:none }

  .stmt__notes{ display:flex; flex-direction:column; gap:22px }
  .stmt__notes p{ grid-column:auto }

  .radial{ height:230vh }
  .radial__t{ font-size:clamp(24px,7.4vw,44px) }

  .brands__t{ max-width:100% }

  /* Kept in proportion with the shorter .foot__inner below: 150vh was sized
     for a 100svh sticky box, and left as dead black space below the box
     once that box was shortened to fit its actual (much shorter, stacked)
     mobile content instead. */
  .foot{ height:100vh }
  /* the reference's phone footer: two columns, values BELOW their labels */
  .foot__cols{ display:grid; grid-template-columns:1fr 1fr;
    gap:clamp(28px,7vw,44px) 6%; font-size:16px }
  .foot__col{ display:block }
  .foot__k{ display:block; margin-bottom:.7em }
  .foot__mark__svg{ width:100% }
  /* .foot__inner's 100svh has a lot more spare room than the (much shorter,
     stacked) mobile content needs, and margin-top:auto on the mark pools
     all of it into one gap above the wordmark. A fixed, modest gap instead
     of "however much space is left" keeps that from ballooning. */
  .foot__inner{ height:auto; min-height:60svh }
  .foot__markwrap{ margin-top:clamp(50px,10vh,100px) }
}

.no-motion .radial__t--b{ display:none }
.no-motion .radial{ height:auto }
.no-motion .radial__pin{ position:relative; height:auto; padding-block:26vh }
.no-motion .brands{ height:auto }
.no-motion .brands__pin{ position:relative; height:auto; padding-block:20vh }
.no-motion .foot{ height:auto }
.no-motion .foot__inner{ position:relative; height:auto }

/* ═══════════════════════ 13 · contact page ═══════════════════════ */
/* The statement runs at display size so the page opens on the sentence
   itself rather than on a form. Centred, matching the reference. No fixed
   100svh: the block is as tall as the words need, and what follows starts
   right under them. */
.cintro{
  background:var(--paper); text-align:center;
  padding:clamp(110px,15vh,210px) var(--pad) clamp(50px,7vw,110px);
}
.cintro__t{
  max-width:22ch; margin:0 auto clamp(22px,2.8vw,38px);
  font-family:var(--serif); font-weight:400;
  font-size:clamp(34px,6.6vw,112px); line-height:1.05; letter-spacing:-.014em;
}
.cintro__d{
  max-width:54ch; margin:0 auto;
  font-family:var(--sans); font-weight:400; color:var(--muted);
  font-size:clamp(16px,1.4vw,21px); line-height:1.5;
}

/* ── how to reach us ──────────────────────────────────────────────
   Three columns, but only the middle one holds content: the value is
   centred on the page and the label is pushed to the inside edge of the
   left column, which is what hangs it in the gutter beside the value
   instead of indenting the value to make room for it. align-items:baseline
   sets the label on the value's FIRST baseline, so a value that wraps still
   has its label level with its opening line. */
.creach{
  background:var(--paper);
  padding:clamp(20px,3vw,44px) var(--pad) clamp(70px,9vw,150px);
}
.creach__row{
  display:grid; grid-template-columns:1fr auto 1fr;
  column-gap:clamp(18px,3vw,56px); align-items:baseline;
  padding:clamp(12px,1.8vw,26px) 0;
}
.creach__k{
  grid-column:1; justify-self:end; text-align:right;
  font-family:var(--sans); font-weight:400; color:var(--muted);
  font-size:var(--micro); line-height:1.3; letter-spacing:.03em;
}
.creach__v{
  grid-column:2; margin:0; text-align:center;
  font-family:var(--serif); font-weight:400; color:var(--ink);
  font-size:clamp(26px,4.6vw,76px); line-height:1.14; letter-spacing:-.012em;
}
/* Underline on hover only: at this size a permanent rule under every value
   would read as three heavy bars down the middle of the page. */
.creach__v a{
  color:inherit; text-decoration:none;
  transition:opacity .25s var(--ease);
}
.creach__v a:hover{ text-decoration:underline; text-underline-offset:.12em }

.cband{ background:var(--paper) }
.cband img{
  display:block; width:100%;
  height:clamp(280px,52vw,780px); object-fit:cover;
}
.cband__map{
  display:block; width:100%; border:0;
  height:clamp(280px,52vw,780px);
}

/* Label ABOVE the address, not hanging beside it. The reach rows above can
   carry a hanging label because their values are single short lines; this
   one is three lines deep, so a label out in the left column had nothing to
   sit against and read as a stray word half a page away from the address. */
.caddr{
  background:var(--paper);
  display:flex; flex-direction:column; align-items:center;
  gap:clamp(8px,1.2vw,16px); text-align:center;
  padding:clamp(24px,3vw,48px) var(--pad) clamp(80px,10vw,170px);
}
.caddr__k{
  font-family:var(--sans); font-weight:400; color:var(--muted);
  font-size:var(--micro); line-height:1.3; letter-spacing:.03em;
}
.caddr__v{
  margin:0;
  font-family:var(--serif); font-weight:400; color:var(--ink);
  font-size:clamp(24px,3.6vw,58px); line-height:1.18; letter-spacing:-.012em;
}

@media (max-width:820px){
  /* One column: the hanging label has nowhere to hang, so it sits above its
     value as a plain caption and everything aligns left. */
  .creach__row{
    grid-template-columns:1fr; row-gap:.35em;
  }
  .creach__k{
    grid-column:1; justify-self:start; text-align:left;
  }
  .creach__v{ grid-column:1; text-align:left }
  /* .caddr is already a stacked column — it just needs to stop centring. */
  .caddr{ align-items:flex-start; text-align:left }
}

.connect{
  background:var(--void); color:var(--ink-i);
  padding:clamp(80px,10vw,170px) var(--pad);
}
.connect__head{ max-width:640px; margin-bottom:clamp(40px,5vw,64px) }
.connect__t{
  font-family:var(--serif); font-weight:400; margin:0 0 .5em;
  font-size:clamp(30px,4.2vw,60px); line-height:1.08; letter-spacing:-.012em;
}
.connect__d{
  font-family:var(--sans); font-size:clamp(15px,1.2vw,18px); color:var(--muted-i);
  line-height:1.5; margin:0;
}
.connect__list{ display:flex; flex-direction:column }
.connect__a{
  display:flex; align-items:center; justify-content:space-between;
  padding:clamp(18px,2.4vw,30px) 0; border-top:1px solid #2a2a2a;
  font-family:var(--serif); font-size:clamp(22px,3vw,44px); letter-spacing:-.01em;
  transition:opacity .25s var(--ease);
}
.connect__list .connect__a:last-child{ border-bottom:1px solid #2a2a2a }
.connect__a:hover{ opacity:.6 }
.connect__x{
  font-family:var(--sans); font-size:max(14px,1.1vw); flex-shrink:0; margin-left:1em;
}

.no-motion .radial__t--b{ display:none }
.no-motion .radial{ height:auto }
.no-motion .radial__pin{ position:relative; height:auto; padding-block:26vh }
.no-motion .brands{ height:auto }
.no-motion .brands__pin{ position:relative; height:auto; padding-block:20vh }
.no-motion .foot{ height:auto }
.no-motion .foot__inner{ position:relative; height:auto }

@media (prefers-reduced-motion:reduce){
  *{ animation-duration:.001s !important; transition-duration:.001s !important }
}

/* ═══════════════════════ 14 · careers page ═══════════════════════
   Layout follows figma.com/careers — hero, why-us, values, life, benefits,
   location, then the grouped openings — but every part is built out of this
   site's own pieces: the About page's .ahero and .phil, the contact page's
   hanging label/value pairing, and the .connect row for the listings. */
.is-careers{ background:var(--void); color:var(--ink-i) }

/* Its own crop of the office rather than the About page's team photo, so
   the two heroes are not the same picture twice. */
.ph__fill--careers{
  background:var(--ph) url("https://d1ehi4znk0tdbs.cloudfront.net/moretasks-website-final/img/careers.png") center 30%/cover no-repeat;
}
.ahero .ph__fill--careers{ inset:-16% 0 }

/* ═══════════════════════ 15 · services page ═══════════════════════ */
.is-services{ background:var(--void); color:var(--ink-i) }

.ph__fill--services{
  background:var(--ph) url("https://d1ehi4znk0tdbs.cloudfront.net/moretasks-website-final/img/services.png") center/cover no-repeat;
}
.ahero .ph__fill--services{ inset:-16% 0 }

.ph__fill--services-hero{
  background:var(--ph) url("https://d1ehi4znk0tdbs.cloudfront.net/moretasks-website-final/img/services/service-hero-bg.webp") center 30%/cover no-repeat;
}
.ahero .ph__fill--services-hero{ inset:-16% 0 }

/* ── closing CTA ──────────────────────────────────────────── */
.scta{
  background:var(--paper); color:var(--ink);
  padding:clamp(90px,12vw,180px) var(--pad);
  display:flex; justify-content:center; text-align:center;
}
.scta__row{ max-width:1200px }
.scta__t{
  font-family:var(--sans); font-weight:400; margin:0 0 .5em;
  font-size:clamp(34px,5vw,76px); line-height:1.08; letter-spacing:-.012em;
}
.scta__d{
  margin:0 auto clamp(28px,3.4vw,44px);
  font-family:var(--sans); font-size:clamp(15px,1.25vw,19px);
  line-height:1.5; color:var(--muted); max-width:60ch;
}
.scta__cta{
  display:inline-flex; align-items:center; gap:8px;
  padding:18px 32px 14px; border-radius:999px; border:1px solid rgba(13,13,13,.8);
  font-family:var(--sans); font-weight:500; font-size:18px; line-height:1; color:var(--ink);
  text-decoration:none; transition:background var(--ease), color var(--ease), border-color var(--ease);
}
.scta__cta:hover{ background:var(--ink); border-color:var(--ink); color:var(--ink-i) }
.scta__cta__arrow{ display:inline-flex; align-items:center; line-height:1; margin-right:-.3em }

/* ── values and culture ───────────────────────────────────
   figma.com/careers' arrangement — heading, narrow intro, image-topped
   cards three to a row — in this site's colours and type.

   The row is TOP-aligned and every photo keeps its own aspect ratio, so the
   headings sit at different heights down the row. That stagger is the whole
   point of the layout: five equal cards on a shared baseline would read as
   a table of contents rather than a wall of moments. */
.vals{
  background:var(--void); color:var(--ink-i);
  padding:0 var(--pad) clamp(90px,12vw,200px);
}
.vals__head{ max-width:60ch; margin-bottom:clamp(44px,6vw,96px) }
.vals__t{
  font-family:var(--serif); font-weight:400; margin:0 0 .5em;
  font-size:clamp(30px,4.2vw,60px); line-height:1.08; letter-spacing:-.012em;
}
.vals__lede{
  margin:0; max-width:52ch;
  font-family:var(--sans); font-weight:400; color:var(--muted-i);
  font-size:clamp(15px,1.25vw,19px); line-height:1.5;
}
.vals__grid{
  display:grid; grid-template-columns:repeat(3,1fr);
  align-items:start;                      /* the stagger depends on this */
  gap:clamp(40px,5vw,88px) clamp(24px,3.4vw,60px);
}
.vals__img{
  display:block; width:100%; aspect-ratio:4/3; object-fit:cover;
  margin-bottom:clamp(16px,1.8vw,28px);
  background:var(--ph-dark);
}
.vals__k{
  margin:0 0 .6em;
  font-family:var(--sans); font-weight:400; color:var(--ink-i);
  font-size:clamp(19px,1.9vw,28px); line-height:1.2; letter-spacing:-.012em;
}
.vals__d{
  margin:0; font-family:var(--sans); color:var(--muted-i);
  font-size:clamp(14px,1.15vw,17px); line-height:1.5;
}

/* ── life here: photo left, copy right ───────────────────── */
.clife{
  background:var(--void); color:var(--ink-i);
  display:flex; align-items:stretch; gap:clamp(24px,4vw,72px);
  padding:0 var(--pad) clamp(90px,12vw,200px);
}
.clife__media{
  flex:0 0 52%; position:relative; overflow:hidden;
  min-height:clamp(320px,44vw,620px); background:var(--ph-dark);
}
.ph__fill--life{
  background:var(--ph) url("https://d1ehi4znk0tdbs.cloudfront.net/moretasks-website-final/img/podcast.png") center/cover no-repeat;
}
.clife__copy{
  flex:1 1 0; min-width:0;
  display:flex; flex-direction:column; justify-content:flex-end;
  padding-bottom:clamp(6px,1vw,18px);
}
.clife__t{
  font-family:var(--serif); font-weight:400; margin:0 0 .5em;
  font-size:clamp(28px,3.6vw,52px); line-height:1.08; letter-spacing:-.012em;
}
.clife__d{
  margin:0; max-width:38ch;
  font-family:var(--sans); font-size:clamp(15px,1.2vw,18px);
  line-height:1.5; color:var(--muted-i);
}

/* ── benefits ─────────────────────────────────────────────── */
.perks{
  background:var(--paper); color:var(--ink);
  padding:clamp(80px,11vw,180px) var(--pad) clamp(70px,9vw,150px);
}
.perks__t{
  font-family:var(--serif); font-weight:400; margin:0 0 clamp(36px,5vw,80px);
  font-size:clamp(30px,4.2vw,60px); line-height:1.08; letter-spacing:-.012em;
}
.perks__grid{
  display:grid; grid-template-columns:repeat(4,1fr);
  gap:clamp(28px,3.4vw,60px) clamp(24px,3.4vw,60px);
}
.perks__i{ border-top:1px solid #e6e6e6; padding-top:clamp(14px,1.6vw,24px) }
.perks__i:nth-child(-n+4){ border-top:none }
.perks__k{
  display:block; margin-bottom:.8em;
  font-family:var(--sans); font-size:var(--micro); letter-spacing:.03em;
  text-transform:uppercase; color:var(--muted);
}
.perks__d{
  margin:0; font-family:var(--sans);
  font-size:clamp(15px,1.25vw,19px); line-height:1.45; color:var(--ink);
}

/* ── location: the contact page's hanging label/value ─────── */
.cloc{
  background:var(--paper); color:var(--ink);
  display:grid; grid-template-columns:1fr auto 1fr;
  column-gap:clamp(18px,3vw,56px); align-items:baseline;
  padding:0 var(--pad) clamp(90px,11vw,180px);
}
.cloc__k{
  grid-column:1; justify-self:start;
  font-family:var(--sans); color:var(--muted);
  font-size:var(--micro); line-height:1.3; letter-spacing:.03em;
}
.cloc__v{
  grid-column:2; margin:0; text-align:center;
  font-family:var(--serif); font-weight:400; color:var(--ink);
  font-size:clamp(22px,3vw,48px); line-height:1.18; letter-spacing:-.012em;
}

/* ── the openings ─────────────────────────────────────────── */
.jobs{
  background:var(--paper); color:var(--ink);
  padding:0 var(--pad) clamp(60px,8vw,120px);
  /* the header is fixed, so an anchor jump has to clear it */
  scroll-margin-top:clamp(56px,7vw,92px);
}
.jobs__head{ max-width:640px; margin-bottom:clamp(40px,5vw,72px) }
.jobs__t{
  font-family:var(--serif); font-weight:400; margin:0 0 .5em;
  font-size:clamp(34px,5.4vw,88px); line-height:1.04; letter-spacing:-.014em;
}
.jobs__d{
  margin:0; font-family:var(--sans); color:var(--muted);
  font-size:clamp(15px,1.2vw,18px); line-height:1.5;
}
/* ── search + team filters ────────────────────────────────
   Only rendered under .js: without the script they would be dead furniture
   in front of a list that reads perfectly well on its own. */
.jobf{ display:none }
.js .jobf{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:clamp(14px,1.6vw,22px) clamp(16px,2vw,28px);
  margin-bottom:clamp(30px,4vw,64px);
}
/* A ruled field rather than a boxed one — the same hairline the job rows
   and the old form inputs use, so it belongs to this page. */
.jobf__search{ flex:1 1 240px; max-width:340px; display:block }
.jobf__input{
  width:100%; border:0; border-bottom:1px solid var(--ink); border-radius:0;
  background:none; padding:.55em 0; outline:none;
  font-family:var(--sans); font-size:clamp(14px,1.05vw,16px); color:var(--ink);
  -webkit-appearance:none; appearance:none;
}
.jobf__input::placeholder{ color:var(--muted) }
.jobf__input:focus-visible{ border-bottom-width:2px; padding-bottom:calc(.55em - 1px) }

.jobf__chips{ display:flex; flex-wrap:wrap; gap:8px }
/* Same pill as the values sound toggle, inverted for light ground. */
.jobf__chip{
  display:inline-flex; align-items:flex-end; gap:.5em;
  padding:.55em 1em; border:1px solid #dcdcdc; border-radius:999px;
  background:none; color:var(--ink); cursor:pointer;
  font-family:var(--sans); font-size:var(--micro); letter-spacing:.03em;
  text-transform:uppercase; line-height:1.3; white-space:nowrap;
  transition:background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.jobf__chip:hover{ border-color:var(--ink) }
.jobf__chip.is-on{ background:var(--ink); border-color:var(--ink); color:var(--paper) }
.jobf__n{ font-size:.86em; opacity:.5 }
/* A team with nothing left after a search is still worth showing as a
   disabled option — hiding chips would make the row jump on every keystroke. */
.jobf__chip[disabled]{ opacity:.32; cursor:default }
.jobf__chip[disabled]:hover{ border-color:#dcdcdc }

.jobf__count{
  margin:0 0 0 auto; flex-shrink:0;
  font-family:var(--sans); font-size:var(--micro); letter-spacing:.03em;
  text-transform:uppercase; color:var(--muted);
}

.jobs__none{
  margin:0; padding:clamp(24px,3vw,44px) 0; border-top:1px solid #e6e6e6;
  font-family:var(--sans); font-size:clamp(15px,1.2vw,18px); color:var(--muted);
}
.jobs__none a{ color:var(--ink) }

.jobs__group + .jobs__group{ margin-top:clamp(44px,5.5vw,88px) }
.jobs__k{
  margin:0 0 clamp(8px,1vw,16px);
  font-family:var(--sans); font-weight:400; color:var(--ink);
  font-size:clamp(20px,2.2vw,32px); line-height:1.2; letter-spacing:-.012em;
}
.jobs__list{ display:flex; flex-direction:column }
/* The .connect row, inverted for light ground: title left, meta right, rule
   above, and the whole row is the target rather than just the words. */
.job{
  display:flex; align-items:baseline; justify-content:space-between; gap:1.5em;
  padding:clamp(15px,1.9vw,26px) 0; border-top:1px solid #e6e6e6;
  color:var(--ink); text-decoration:none;
  transition:opacity .25s var(--ease);
}
.jobs__list .job:last-child{ border-bottom:1px solid #e6e6e6 }
.job:hover{ opacity:.55 }
.job__t{
  font-family:var(--serif); font-weight:400;
  font-size:clamp(18px,1.9vw,30px); line-height:1.2; letter-spacing:-.008em;
}
.job__meta{
  flex-shrink:0; display:flex; align-items:baseline; gap:clamp(10px,1.4vw,26px);
  font-family:var(--sans); font-size:var(--micro); color:var(--muted);
  letter-spacing:.03em; text-transform:uppercase;
}
.job__x{ font-size:max(13px,1vw); color:var(--ink) }

/* ── open application ─────────────────────────────────────── */
.capply{
  background:var(--paper); color:var(--ink);
  padding:clamp(50px,7vw,110px) var(--pad) clamp(90px,11vw,180px);
}
.capply__row{
  display:grid; grid-template-columns:1fr auto 1fr;
  column-gap:clamp(18px,3vw,56px); align-items:baseline;
}
.capply__k{
  grid-column:1; justify-self:end; text-align:right;
  font-family:var(--sans); color:var(--muted);
  font-size:var(--micro); line-height:1.3; letter-spacing:.03em;
}
.capply__v{
  grid-column:2; margin:0; text-align:center;
  font-family:var(--serif); font-weight:400;
  font-size:clamp(26px,4.6vw,76px); line-height:1.14; letter-spacing:-.012em;
}
.capply__v a{ color:inherit; text-decoration:none }
.capply__v a:hover{ text-decoration:underline; text-underline-offset:.12em }

@media (max-width:820px){
  /* Two up on tablet, one on phone — the stagger still reads at two. */
  .vals__grid{ grid-template-columns:repeat(2,1fr) }
  .perks__grid{ grid-template-columns:1fr }
  .perks__i:nth-child(-n+4){ border-top:1px solid #e6e6e6 }
  .perks__i:first-child{ border-top:none }
  .scta__t br{ display:none }
  .clife{ flex-direction:column }
  .clife__media{ flex:0 0 auto; min-height:58vw }
  .cloc, .capply__row{ grid-template-columns:1fr; row-gap:.35em }
  .cloc__k, .capply__k{ grid-column:1; justify-self:start; text-align:left }
  .cloc__v, .capply__v{ grid-column:1; text-align:left }
  /* The meta drops under the title rather than squeezing it to nothing. */
  .job{ flex-direction:column; align-items:flex-start; gap:.5em }
  .jobf__search{ max-width:none; flex-basis:100% }
  .jobf__count{ margin-left:0 }
}
@media (max-width:560px){
  .vals__grid{ grid-template-columns:1fr }
}

/* ═══════════════════ 15 · services: the four capabilities ═══════════════════
   Figma "MoreTasks Website" 69:35 / 69:40 / 69:45 / 69:50. The frame is
   1440x1024: copy at x=61 (4.24vw) on a 520px column (36vw), title 52px
   Medium at -1.04px tracking, caption 24px in rgba(110,110,110,.93) — which
   is this sheet's --muted-i — and the photograph pinned from x=704 (48.9%)
   to the right edge.

   One pinned viewport carries all four. The photographs are stacked in DOM
   order and the incoming one is revealed by opening its clip-path inset
   downwards, scrubbed to scroll (see main.js) — a hard horizontal edge
   travelling down the frame rather than a dissolve. */
/* (stages + 1) * 100vh, where the stages are the opening statement plus the
   six services — eight. The pin eats one viewport and each stage wants a
   hold and a wipe. main.js counts the pairs it finds, so only this
   multiplier needs touching if the count changes. */
.svc{
  position:relative; height:calc(8 * 100vh);
  background:var(--void); color:var(--ink-i);
}
.svc__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  background:var(--void);
}

/* Right of 48.9%, bleeding to the top, right and bottom edges. */
.svc__media{
  position:absolute; inset:0 0 0 48.9%;
  overflow:hidden; background:var(--ph-dark);
}
.svc__media img{ width:100%; height:100%; object-fit:cover; display:block }
/* ALL of them parked closed, not just the ones after the first: the strip
   opens on the statement over a black viewport, and the first photograph
   wipes in from there. Gated on .js (set inline in <head>) so that without
   the script they simply stack rather than the page painting the last
   photograph and then snapping. */
.js .svc__media{ clip-path:inset(100% 0% 0% 0%) }

/* The left column: section heading on top, the cycling service copy under
   it, the pair centred together. Figma puts the service alone at the
   vertical centre, but the heading has to live somewhere and stranding it
   at the top of the viewport left a screen of black between the two. */
.svc__panel{
  position:absolute; inset:0 51.1% 0 0; z-index:2;
  display:flex; flex-direction:column; justify-content:center;
  padding:0 clamp(20px,4.24vw,61px);
}
/* The opening statement, Figma 69:132: 92px Medium at -1.84px on a 740px
   column. It runs wider than the panel on purpose — at this stage every
   photograph is still closed, so the extra width is over black. */
.svc__copy--intro{ width:min(51.4vw,740px) }
.svc__it{
  margin:0 0 .3em;
  font-family:var(--sans); font-weight:500; color:var(--ink-i);
  font-size:clamp(30px,6.4vw,92px); line-height:1.1; letter-spacing:-.02em;
}
.svc__id{
  margin:0;
  font-family:var(--sans); font-weight:400; color:var(--muted-i);
  font-size:clamp(14px,1.67vw,24px); line-height:1.34;
}
/* All six in one grid cell: they stack, and the box takes the height of the
   longest one, so nothing below shifts as they cycle. */
.svc__stack{ display:grid }
.svc__copy{
  grid-area:1/1;
  display:flex; flex-direction:column; gap:clamp(10px,1.1vw,16px);
}
.js .svc__stack .svc__copy + .svc__copy{ opacity:0; visibility:hidden }
.svc__t{
  margin:0; font-family:var(--sans); font-weight:500; color:var(--ink-i);
  font-size:clamp(30px,3.6vw,52px); line-height:1.1; letter-spacing:-.02em;
}
.svc__d{
  margin:0; max-width:min(34vw,500px);
  font-family:var(--sans); font-weight:400; color:var(--muted-i);
  font-size:clamp(15px,1.67vw,24px); line-height:1.34;
}

@media (max-width:820px){
  /* No pin under this breakpoint (main.js skips the sequence), so the four
     read as four normal blocks: caption over its photograph. */
  .svc{ height:auto }
  .svc__pin{ position:relative; height:auto; overflow:visible; display:flex; flex-direction:column }
  .svc__media{
    position:relative; inset:auto; order:2;
    aspect-ratio:4/3; clip-path:none;
  }
  /* Same selector as the desktop rule that parks them closed, or that one
     wins on specificity and the photographs stay clipped away entirely. */
  .js .svc__media{ clip-path:none }
  /* display:contents dissolves the panel and the stack, so the heading and
     the six captions become flex children of .svc__pin alongside the
     photographs and can be ordered against them. */
  .svc__panel, .svc__stack{
    display:contents;
  }
  .svc__copy--intro{
    width:auto; order:0;
    padding:clamp(56px,13vw,90px) var(--pad) clamp(10px,3vw,20px);
  }
  .svc__copy{
    position:relative; width:auto;
    padding:clamp(28px,7vw,44px) var(--pad) clamp(20px,5vw,30px);
  }
  .js .svc__stack .svc__copy + .svc__copy{ opacity:1; visibility:visible }
  .svc__d{ max-width:44ch }
  /* Ordered by data-i, not by position: with the panel dissolved the flat
     child list is six photographs, the heading, then six captions, and any
     positional rule would have to be rewritten every time one is added. */
  .svc__copy[data-i="1"]{ order:1 }   .svc__media[data-i="1"]{ order:2 }
  .svc__copy[data-i="2"]{ order:3 }   .svc__media[data-i="2"]{ order:4 }
  .svc__copy[data-i="3"]{ order:5 }   .svc__media[data-i="3"]{ order:6 }
  .svc__copy[data-i="4"]{ order:7 }   .svc__media[data-i="4"]{ order:8 }
  .svc__copy[data-i="5"]{ order:9 }   .svc__media[data-i="5"]{ order:10 }
  .svc__copy[data-i="6"]{ order:11 }  .svc__media[data-i="6"]{ order:12 }
}

/* ═══════════════ 14c · services: what makes us different ═══════════════
   Figma 69:112 (1440x1024). Heading 64px Medium at -1.28px on a 620px
   column from x=84; the list column is 542px wide centred on x=1115, items
   roughly 240px apart, the active one sharp and the rest at 40% behind a
   2px blur.

   One pinned viewport: the list is static and only the focus moves down it
   as you scroll, which is what the frame shows — three items stacked with
   one of them clear. */
.diff{
  position:relative; height:400svh;
  background:var(--paper); color:var(--ink);
}
.diff__pin{
  position:sticky; top:0; height:100svh; overflow:hidden;
  background:var(--paper);
}

.diff__head{
  position:absolute; left:clamp(20px,5.83vw,84px); width:min(43vw,620px);
  top:25.4%; transform:translateY(-50%);
}
.diff__ht{
  margin:0 0 .32em;
  font-family:var(--sans); font-weight:500; color:var(--ink);
  font-size:clamp(28px,4.44vw,64px); line-height:1.12; letter-spacing:-.02em;
}
.diff__hd{
  margin:0;
  font-family:var(--sans); font-weight:400; color:var(--muted);
  font-size:clamp(14px,1.67vw,24px); line-height:1.34;
}

.diff__list{
  position:absolute; left:58.6%; width:min(37.6vw,542px);
  top:50%; transform:translateY(-50%);
  margin:0; padding:0; list-style:none;
  display:flex; flex-direction:column; gap:clamp(28px,6.4vh,84px);
}
/* On desktop main.js (§17) writes opacity / blur / offset every frame as a
   continuous function of scroll, so no transition here — it would only lag
   behind the wheel and fight the inline values. These rules are the resting
   state for the no-JavaScript and reduced-motion cases. */
.diff__i{
  opacity:.38; filter:blur(.8px);
}
.diff__i.is-on{ opacity:1; filter:blur(0) }
@media (min-width:821px) and (prefers-reduced-motion:no-preference){
  html.js .diff__i{ will-change:transform,opacity,filter }
}
.diff__t{
  margin:0 0 .26em;
  font-family:var(--sans); font-weight:500; color:var(--ink);
  font-size:clamp(26px,4.17vw,60px); line-height:1.2; letter-spacing:-.02em;
}
.diff__d{
  margin:0;
  font-family:var(--sans); font-weight:400; color:var(--ink);
  font-size:clamp(14px,1.67vw,24px); line-height:1.34;
}

@media (max-width:820px), (prefers-reduced-motion:reduce){
  /* No pin under this breakpoint (main.js skips it), so the heading and the
     list read as one column and every item is legible — a blurred item in a
     static list is just unreadable text. */
  .diff{ height:auto }
  .diff__pin{ position:relative; height:auto; overflow:visible }
  .diff__head{
    position:relative; left:auto; top:auto; transform:none; width:auto;
    padding:clamp(70px,16vw,110px) var(--pad) clamp(30px,8vw,48px);
  }
  .diff__list{
    position:relative; left:auto; top:auto; transform:none; width:auto;
    padding:0 var(--pad) clamp(70px,16vw,110px);
    gap:clamp(26px,7vw,44px);
  }
  .diff__i, .diff__i.is-on{ opacity:1; filter:none }
}

/* ═════════════════════ mobile finish pass ═════════════════════
   The desktop header contains five links and cannot remain a single line at
   phone widths. The script adds the two-line toggle; without JavaScript the
   original navigation remains visible as a compact wrapping fallback. */
.menu-toggle{ display:none }

:where(a,button,input):focus-visible{
  outline:2px solid currentColor;
  outline-offset:4px;
}

@media (max-width:820px){
  :root{
    --pad:20px;
    --micro:12px;
    --nav:16px;
  }

  body.menu-open{ overflow:hidden }

  .hdr{
    min-height:64px;
    align-items:center;
    padding:max(10px,env(safe-area-inset-top))
            max(var(--pad),env(safe-area-inset-right)) 10px
            max(var(--pad),env(safe-area-inset-left));
    color:#fff;
    background:transparent;
    mix-blend-mode:difference;
  }
  .hdr.is-menu-open{ mix-blend-mode:normal }
  .hdr.is-away:not(.is-menu-open),
  .hdr.is-gone:not(.is-menu-open){ opacity:0; pointer-events:none }
  .hdr .mark{ position:relative; z-index:2 }
  .mark__svg{ height:20px; width:auto }

  .has-mobile-menu .menu-toggle{
    position:relative; z-index:3;
    display:grid; place-content:center; gap:6px;
    width:44px; height:44px; margin:-4px -8px -4px 0;
    padding:0; border:0; border-radius:50%;
    background:transparent; color:#fff; cursor:pointer;
  }
  .menu-toggle span{
    display:block; width:22px; height:1px; background:currentColor;
    transform-origin:center; transition:transform .3s var(--ease),opacity .2s ease;
  }
  .hdr.is-menu-open .menu-toggle span:first-child{ transform:translateY(3.5px) rotate(45deg) }
  .hdr.is-menu-open .menu-toggle span:last-child{ transform:translateY(-3.5px) rotate(-45deg) }

  .hdr.has-mobile-menu .nav{
    position:fixed; inset:0; z-index:1;
    display:flex; flex-direction:column; align-items:stretch; justify-content:center;
    gap:0; padding:calc(84px + env(safe-area-inset-top)) var(--pad) max(30px,env(safe-area-inset-bottom));
    background:#050505; color:#fff;
    opacity:0; visibility:hidden; pointer-events:none;
    transform:translateY(-12px);
    transition:opacity .3s var(--ease),transform .3s var(--ease),visibility 0s linear .3s;
  }
  .hdr.has-mobile-menu.is-menu-open .nav{
    opacity:1; visibility:visible; pointer-events:auto; transform:none;
    transition:opacity .3s var(--ease),transform .3s var(--ease),visibility 0s;
  }
  .has-mobile-menu .nav__a{
    display:flex; align-items:center;
    min-height:58px; border-top:1px solid #303030;
    font-family:var(--serif); font-size:clamp(30px,10vw,44px); line-height:1;
  }
  .has-mobile-menu .nav__a:last-child{ border-bottom:1px solid #303030 }
  .has-mobile-menu .nav__a.is-on{ text-decoration:none }
  .has-mobile-menu .nav__a.is-on::before{
    content:""; width:7px; height:7px; margin-right:12px;
    border-radius:50%; background:currentColor;
  }

  /* Keep important controls comfortably tappable. */
  .connect__a{ min-height:60px }
  .jobf__chip{ min-height:44px; padding:.7em 1em }
  .jobf__input{ min-height:44px }
  .job{ min-height:64px }

  /* Slightly calmer vertical rhythm on phones, particularly on the long
     About/Careers pages. */
  .statement{ padding-top:clamp(64px,18vw,92px); padding-bottom:clamp(56px,15vw,80px) }
  .connect,.perks{ padding-top:clamp(64px,18vw,96px); padding-bottom:clamp(64px,18vw,96px) }
  .mates__head{ padding-top:clamp(64px,18vw,96px) }
  .vals{ padding-bottom:clamp(70px,20vw,110px) }
  .clife{ padding-bottom:clamp(70px,20vw,110px) }
  .cintro{ padding-top:clamp(112px,30vw,140px) }

  /* Dynamic viewport units follow iOS Safari's expanding/collapsing chrome,
     preventing a stale strip at the top or bottom of full-screen scenes. */
  .hero__pin,
  .radial__pin,
  .value__pin,
  .brands__pin,
  .ahero{ height:100dvh }

  .foot__inner{
    padding-right:max(var(--pad),env(safe-area-inset-right));
    padding-bottom:max(12px,env(safe-area-inset-bottom));
    padding-left:max(var(--pad),env(safe-area-inset-left));
  }
}

@media (max-width:380px){
  :root{ --pad:16px }
  .hero__title{ font-size:clamp(27px,9vw,34px) }
  .hero__title .ln__i.serif{ font-size:clamp(20px,6.3vw,25px) }
  .ahero__t{ max-width:calc(100% - 32px) }
  .foot__cols{ column-gap:10% }
}

/* ═══════════════════════ 16 · legal pages ═══════════════════════ */
.legal{
  background:var(--paper); color:var(--ink);
  padding:calc(140px + env(safe-area-inset-top)) var(--pad) clamp(90px,12vw,160px);
}
.legal__inner{ max-width:760px; margin:0 auto }
.legal__t{
  font-family:var(--serif); font-weight:400; margin:0 0 .3em;
  font-size:clamp(32px,4.4vw,60px); line-height:1.08; letter-spacing:-.012em;
}
.legal__updated{
  margin:0 0 clamp(40px,5vw,64px);
  font-family:var(--sans); font-size:var(--micro); color:var(--muted);
  letter-spacing:.03em; text-transform:uppercase;
}
.legal__inner h2{
  font-family:var(--sans); font-weight:600; margin:1.8em 0 .6em;
  font-size:clamp(18px,1.6vw,24px); line-height:1.25; letter-spacing:-.006em;
}
.legal__inner h2:first-of-type{ margin-top:0 }
.legal__inner p{
  margin:0 0 1.1em; font-family:var(--sans);
  font-size:clamp(15px,1.15vw,18px); line-height:1.6; color:var(--ink);
}
.legal__inner ul{
  margin:0 0 1.1em; padding-left:1.2em;
  font-family:var(--sans); font-size:clamp(15px,1.15vw,18px); line-height:1.6;
}
.legal__inner li{ margin-bottom:.6em }
.legal__inner li strong{ font-weight:600 }
.legal__inner a{ color:inherit }
