:root {
  --cement: #ebe6dc;
  --plaster: #f4f0e9;
  --mortar: #d5cec2;
  --ink: #1c1a17;
  --ink-2: #565047;
  --ink-3: #8a8175;
  --poured: #2b2825;
  --sans: "Instrument Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --block: "Archivo", "Helvetica Neue", Arial, sans-serif;
  color-scheme: light;
  --barh: 90px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
  margin: 0;
  background: var(--plaster);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }

.wrap { max-width: 1320px; margin: 0 auto; padding-left: 5.5%; padding-right: 5.5%; }
@media (min-width: 1440px) { .wrap { padding-left: 48px; padding-right: 48px; } }

/* ---------- hero ---------- */
/* the hero is the opening screen: it fills the viewport so the photograph is the
   whole first impression. svh is the small viewport height, so a phone that hides
   its address bar on scroll still gets one screen exactly rather than a hero that
   jumps as the chrome collapses; the vh above it is the fallback. */
.hero { position: relative; overflow: hidden; background: var(--poured); min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; }
.hero .bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 62%; }
/* the scrim comes off the ink token so it warms with the ground. The flat rgba
   is the same colour, kept as a fallback because losing the scrim would drop the
   contrast under the hero line. */
.hero .shade { position: absolute; inset: 0;
  /* A scrim at each end rather than a flat wash over everything. The bar needs a
     dark ground for the white lockup and the headline needs one for the white
     type; the middle of the hero needs neither, so the photograph is left alone
     there. Measured against the warm ink: 4.60:1 behind the bar, 4.63:1 behind
     the headline. The old flat 50 percent wash held the whole picture at 0.05
     luminance, which is why nothing put there ever read. */
  background: linear-gradient(to bottom,
    rgba(28, 26, 23, 0.54) 0%, rgba(28, 26, 23, 0.54) 14%,
    rgba(28, 26, 23, 0) 32%, rgba(28, 26, 23, 0) 56%,
    rgba(28, 26, 23, 0.68) 80%, rgba(28, 26, 23, 0.68) 100%);
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--ink) 54%, transparent) 0%,
    color-mix(in srgb, var(--ink) 54%, transparent) 14%,
    color-mix(in srgb, var(--ink) 0%, transparent) 32%,
    color-mix(in srgb, var(--ink) 0%, transparent) 56%,
    color-mix(in srgb, var(--ink) 68%, transparent) 80%,
    color-mix(in srgb, var(--ink) 68%, transparent) 100%); }

.bar { position: relative; color: #fff; }
.bar .wrap { display: flex; justify-content: space-between; align-items: center; gap: 24px; padding-top: 26px; padding-bottom: 24px; border-bottom: 1px solid rgba(255, 255, 255, 0.18); }
.bar .mark { width: 152px; }
/* the two lockups sit in one grid cell so the bar can cross-fade white to ink
   without the header changing width; pages that carry only the white one are
   unaffected, a single item in a one-cell grid lays out as it always did */
.bar .home { display: grid; flex: none; }
.bar .home > picture { grid-area: 1 / 1; display: block; transition: opacity 0.2s; }
.bar .home .mark-ink { opacity: 0; }
.bar nav ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 34px; font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap;
  /* the J drops below the baseline, so the lockup's box centre sits under its cap
     band; lift the menu to meet the letters rather than the box */
  transform: translateY(-6px); }
/* the links are 12px of text, which is a small thing to hit with a thumb, so the
   anchor is padded out to a ~30px target and pulled back by the same amount */
.bar nav a { display: inline-block; padding: 9px 0; margin: -9px 0; text-decoration: none; opacity: 0.82; }
.bar nav a:hover, .bar nav a:focus-visible { opacity: 1; }

/* the top bar is pinned: transparent over the hero, poured dark once the page scrolls */
.topbar { position: fixed; top: 0; left: 0; right: 0; z-index: 20; transition: background-color 0.2s;
  /* Over the hero the bar carries blur and no tint of its own, because the scrim
     beneath it already holds the contrast. Below the fold .solid adds a ground. */
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.topbar.solid { background: rgba(43, 40, 37, 0.94); background: color-mix(in srgb, var(--poured) 94%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.topbar.solid .wrap { border-bottom-color: rgba(255, 255, 255, 0.1); }
/* On the home page the scrolled bar stays frosted rather than going to a slab:
   the blur keeps doing the work and the plaster tint is thin enough that the page
   still moves through it. White type cannot survive that. The ground below the
   hero is plaster, where white measures 1.1:1, so the bar turns its contents to
   ink and shows the dark lockup. Measured on the ink: 15.3:1 over the plaster
   sections, and 8.8:1 at the worst case, where the bar sits over the poured
   footer. Sub pages are excluded: their bar is poured at every scroll position,
   so it keeps the white lockup. */
body:not(.sub) .topbar.solid { background: rgba(244, 240, 233, 0.72); background: color-mix(in srgb, var(--plaster) 72%, transparent);
  color: var(--ink); }
body:not(.sub) .topbar.solid .wrap { border-bottom-color: rgba(28, 26, 23, 0.12); }
body:not(.sub) .topbar.solid .mark-lite { opacity: 0; }
body:not(.sub) .topbar.solid .mark-ink { opacity: 1; }
.hero { padding-top: var(--barh); }
section { scroll-margin-top: calc(var(--barh) - 20px); }
@media (prefers-reduced-motion: reduce) { .topbar { transition: none; } }
/* the sub pages have no hero, so there is no photograph for the bar to sit over
   and no fold to cross: they carry the frosted treatment at every scroll
   position, which is the home page's scrolled bar exactly. Their lockup is the
   dark one in the markup rather than a cross-fade, because it never changes
   state. Ink measures 15.3:1 over the plaster the pages are set on, and 8.8:1 at
   the foot, where the bar crosses the poured footer. */
.sub .topbar { background: rgba(244, 240, 233, 0.72); background: color-mix(in srgb, var(--plaster) 72%, transparent);
  color: var(--ink); }
.sub .topbar .wrap { border-bottom-color: rgba(28, 26, 23, 0.12); }
.sub main { padding-top: var(--barh); }
.bar nav a[aria-current="page"] { opacity: 1; text-decoration: underline; text-underline-offset: 7px; text-decoration-thickness: 1px; }

/* ---------- page head: how every page after the home page opens ---------- */
.page-head .wrap { padding-top: 64px; padding-bottom: 40px; display: grid; grid-template-columns: 1fr; gap: 18px 48px; }
@media (min-width: 860px) { .page-head .wrap { grid-template-columns: 1.4fr 1fr; align-items: end; } }
.page-head h1 { margin: 0; font-weight: 400; font-size: clamp(28px, calc(25px + 0.77vw), 36px); line-height: 1.15; letter-spacing: -0.02em; max-width: 24ch; text-wrap: balance; }
.page-head p { margin: 0; color: var(--ink-2); max-width: 46ch; }

/* ---------- home index: where the rest of the site is ---------- */
.index .wrap { padding-bottom: 84px; }
.index ul { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--mortar); }
.index li { border-bottom: 1px solid var(--mortar); }
.index a { display: grid; grid-template-columns: 1fr; gap: 2px 32px; padding: 18px 0; text-decoration: none; }
@media (min-width: 640px) { .index a { grid-template-columns: 180px 1fr; align-items: baseline; } }
.index a .name { font-family: var(--block); font-weight: 700; font-size: 18px; letter-spacing: -0.01em; }
.index a .line { color: var(--ink-2); font-size: 14px; }
.index a:hover .name, .index a:focus-visible .name { text-decoration: underline; text-underline-offset: 4px; }

/* On a phone the full lockup and four menu items cannot share a line without
   crowding, so the top bar carries the monogram alone and the footer, which has
   the room, keeps the whole lockup. */
@media (max-width: 640px) {
  :root { --barh: 69px; }
  /* phones keep the tighter crop; the wide file is mostly filler flutes at 390px */
  .hero .bg { object-position: center bottom; }
  /* the hero fills the phone screen too. The block stays anchored to the bottom,
     so the line still lands low in the frame rather than floating in the middle;
     what changes is that the glass above it now runs to the top of the screen
     instead of stopping short, and the statement below starts under the fold. */
  .hero { min-height: 100vh; min-height: 100svh; }
  .bar .wrap { padding-top: 18px; padding-bottom: 17px; gap: 20px; }
  .topbar .mark { width: 44px; }
  .foot .mark { width: 124px; }
  /* the footer is not pinned, so it can afford the whole lockup on its own row */
  .foot .wrap { flex-wrap: wrap; row-gap: 16px; }
  .bar nav ul { gap: 17px; font-size: 11px; letter-spacing: 0.08em; }
  /* the J hangs below the cap band, so the menu meets the letters, not the box */
  .topbar nav ul { transform: translateY(-5px); }
  .foot nav ul { transform: translateY(-4px); }
}
@media (max-width: 380px) {
  .bar .wrap { gap: 14px; }
  .bar nav ul { gap: 11px; font-size: 10.5px; letter-spacing: 0.03em; }
}

.hero-inner { position: relative; margin-top: auto; }
.hero-inner .wrap { padding-top: 96px; padding-bottom: 72px; display: grid; grid-template-columns: 1fr; gap: 28px 48px; }
@media (min-width: 860px) { .hero-inner .wrap { grid-template-columns: 1.2fr 0.8fr; align-items: end; } }
/* 3.4vw of a phone is 13px, so this clamp bottomed out on every phone and the
   hero read at its smallest where it has the most room. These interpolate from
   a 390px phone to a 1440px desktop instead of resting on the floor. */
.hero h1 { margin: 0; font-family: var(--block); font-weight: 500; font-size: clamp(32px, calc(27.5px + 1.15vw), 44px); line-height: 1.15; letter-spacing: -0.02em; color: #fff; max-width: 24ch; text-wrap: balance; }
.cta { display: inline-block; border: 1px solid currentColor; padding: 14px 24px; font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; text-decoration: none; transition: background 0.15s, color 0.15s; }
.hero .cta { color: #fff; }
.hero .cta:hover, .hero .cta:focus-visible { background: #fff; color: var(--ink); }

/* ---------- statement ---------- */
.statement .wrap { padding-top: 76px; padding-bottom: 64px; display: grid; grid-template-columns: 1fr; gap: 24px 48px; }
@media (min-width: 860px) { .statement .wrap { grid-template-columns: 1.4fr 1fr; } }
.statement h2 { margin: 0; font-weight: 400; font-size: clamp(28px, calc(25px + 0.77vw), 36px); line-height: 1.15; letter-spacing: -0.02em; max-width: 26ch; text-wrap: balance; }
.statement p { margin: 0; color: var(--ink-2); max-width: 46ch; align-self: end; }
/* these sit after the rules they trim, or the base padding wins on order */
@media (max-width: 640px) {
  .hero-inner .wrap { padding-top: 72px; padding-bottom: 56px; }
  .statement .wrap { padding-top: 56px; padding-bottom: 48px; }
}

/* ---------- marks ---------- */
#work .wrap { padding-bottom: 92px; }
/* one list, no groups: four engagements that differ in scope, so the scope is
   stated per project in its caption rather than implied by a section it sits in */
.cases { border-top: 1px solid var(--mortar); padding-top: 40px; display: grid; gap: 52px; }
.case { margin: 0; }
/* the mark and the site it ended up on, side by side. 1fr to 1.2fr because a 4:3
   well and a 16:10 screen land at the same height at that ratio */
.case .art { display: grid; grid-template-columns: 1fr; gap: 18px; }
/* one breakpoint runs this page. Below it the mark and the preview stack, share a
   left edge with the text, and the preview opens on a phone window. Above it they
   sit side by side on a desktop window and fill the column between them. */
@media (max-width: 640px) {
  .case .face, .case .tv-frame { max-width: 440px; }
  /* a phone with browser chrome shows about 620pt of a 390pt page */
  .case .screen { --vw: 390; --vh: 620; }
}
@media (min-width: 641px) { .case .art { grid-template-columns: 1fr 1.2fr; gap: 24px; align-items: start; } }
.case .face { position: relative; aspect-ratio: 4 / 3; background: #fff; border: 1px solid var(--mortar); }
/* a mark drawn for a dark ground gets one, or it washes out */
.case .face.dark { background: var(--poured); border-color: var(--poured); }
.case .face > img { position: absolute; left: 12%; top: 8%; width: 76%; height: 84%; object-fit: contain; }
/* with a before beside it, the new mark moves right so the two never touch */
.case .face.has-before > img { left: 36%; top: 14%; width: 54%; height: 72%; }
.case .before { position: absolute; left: 4%; bottom: 5%; width: 27%; height: 44%; opacity: 0.7; }
.case .before img { width: 100%; height: 100%; object-fit: contain; object-position: left bottom; }
.case figcaption { margin-top: 14px; font-family: var(--block); font-weight: 700; font-size: 16px; display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.case figcaption small { font-family: var(--sans); font-weight: 400; font-size: 13px; color: var(--ink-3); text-align: right; }
/* the name and the scope line cannot share a row on a phone without colliding,
   so the scope drops beneath the name and reads left to right like the rest */
@media (max-width: 640px) {
  .case figcaption { display: block; }
  .case figcaption small { display: block; margin-top: 5px; text-align: left; }
}

/* ---------- work ---------- */
/* the bezel keeps its light to dark run but takes every stop off the ground
   tokens, so it reads as brushed metal in the same light as the page */
.tv-frame { padding: 6px; background: linear-gradient(145deg, var(--plaster) 0%, color-mix(in srgb, var(--mortar) 88%, var(--ink)) 30%, var(--cement) 55%, color-mix(in srgb, var(--mortar) 70%, var(--ink)) 100%); box-shadow: 0 20px 45px color-mix(in srgb, var(--ink) 16%, transparent), 0 3px 9px color-mix(in srgb, var(--ink) 10%, transparent); }
/* the frame renders the client site at --vw wide, so the site itself decides which
   layout to serve. On a phone that is a phone width, which is the layout a phone
   visitor actually wants to see. */
.screen { --vw: 1280; --vh: 800; aspect-ratio: var(--vw) / var(--vh); background: var(--plaster); position: relative; overflow: hidden; container-type: inline-size; }
.screen .ph { position: absolute; inset: 0; display: grid; place-items: center; color: var(--ink-3); font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; text-align: center; padding: 12px; }
.screen iframe { position: absolute; top: 0; left: 0; width: calc(var(--vw) * 1px); height: calc(var(--vh) * 1px); border: 0; transform-origin: 0 0; transform: scale(var(--s, calc(100cqw / var(--vw)))); pointer-events: none; background: var(--plaster); }
.screen .cover { position: absolute; inset: 0; z-index: 2; }
/* ---------- services: operating offer, not four equal tiles ---------- */
.offer { padding-bottom: 92px; }
.offer-lead { padding: 4px 0 48px; border-top: 3px solid var(--ink); }
.offer-lead .label { font-size: 13px; color: var(--ink-3); margin: 0 0 14px; }
.offer-lead h2 { margin: 0 0 16px; font-family: var(--block); font-weight: 800; font-size: clamp(32px, 4.2vw, 52px); letter-spacing: -0.02em; line-height: 1.05; max-width: 14ch; text-wrap: balance; }
.offer-lead > p { margin: 0; color: var(--ink-2); max-width: 46ch; }
.offer-list { display: grid; grid-template-columns: 1fr; }
.offer-item { padding: 26px 0; border-top: 1px solid var(--mortar); }
.offer-item:last-child { border-bottom: 1px solid var(--mortar); }
.offer-item h3 { margin: 0 0 10px; font-family: var(--block); font-weight: 700; font-size: clamp(20px, 2vw, 24px); letter-spacing: -0.01em; }
.offer-item p { margin: 0; color: var(--ink-2); font-size: 14px; max-width: 42ch; }
@media (min-width: 860px) {
  .offer-list { grid-template-columns: 1fr 1fr 1fr; gap: 0 32px; border-top: 1px solid var(--mortar); }
  .offer-item { padding: 32px 0 8px; border-top: none; }
  .offer-item:last-child { border-bottom: none; }
}
@media (max-width: 640px) {
  .offer-lead { padding-bottom: 36px; }
}
/* ---------- services (unused staircase tiles, kept so older markup still paints) ---------- */
.services-head h2 { margin: 0 0 12px; font-weight: 400; font-size: clamp(22px, 2.6vw, 32px); letter-spacing: -0.02em; line-height: 1.15; max-width: 22ch; text-wrap: balance; }
.services-head p { margin: 0; color: var(--ink-2); max-width: 52ch; }
.steps { display: grid; grid-template-columns: 1fr; gap: 20px 32px; margin-top: 44px; }
@media (min-width: 860px) { .steps { grid-template-columns: repeat(4, 1fr); gap: 20px 24px; align-items: end; } }
.step { border-top: 3px solid var(--ink); padding-top: 18px; }
@media (min-width: 860px) {
  .step:nth-child(2) { padding-bottom: 28px; }
  .step:nth-child(3) { padding-bottom: 56px; }
  .step:nth-child(4) { padding-bottom: 84px; }
}
.step h3 { margin: 0 0 10px; font-family: var(--block); font-weight: 800; font-size: clamp(26px, 2.6vw, 32px); letter-spacing: -0.02em; line-height: 1; }
.step p { margin: 0; color: var(--ink-2); font-size: 14px; max-width: 30ch; }
/* stacked, the three columns lose the staircase, so the steps become solid blocks:
   each block is inset one run further and sits directly on the one above, so the
   left silhouette is the stair itself, the way the stair in the L is drawn */
@media (max-width: 859px) {
  .steps { --run: 26px; margin-top: 36px; gap: 0; }
  .step { background: var(--cement); padding: 20px 20px 26px; }
  .step:nth-child(2) { margin-left: var(--run); }
  .step:nth-child(3) { margin-left: calc(var(--run) * 2); }
  .step:nth-child(4) { margin-left: calc(var(--run) * 3); }
}
/* the one real sequence on the page, so it is the one place numbers are allowed */
.process { list-style: none; margin: 44px 0 0; padding: 0; counter-reset: p; max-width: 52ch; font-size: 13px; color: var(--ink-2); }
.process li { counter-increment: p; display: grid; grid-template-columns: 28px 1fr; padding: 9px 0; border-top: 1px solid var(--mortar); }
.process li:last-child { border-bottom: 1px solid var(--mortar); }
.process li::before { content: counter(p); color: var(--ink-3); font-variant-numeric: tabular-nums; }
@media (max-width: 380px) {
  .steps { --run: 18px; }
  .step { padding: 18px 16px 22px; }
}

/* ---------- about ---------- */
.about .wrap { padding-top: 24px; padding-bottom: 92px; display: grid; grid-template-columns: 1fr; gap: 28px 56px; }
@media (min-width: 860px) { .about .wrap { grid-template-columns: 0.42fr 0.58fr; align-items: center; } }
.about .portrait { aspect-ratio: 4 / 5; overflow: hidden; max-width: 420px; }
.about .portrait img { width: 100%; height: 100%; object-fit: cover; }
.about .label { font-size: 13px; color: var(--ink-3); margin: 0 0 14px; }
.about h1, .about h2 { margin: 0 0 16px; font-weight: 400; font-size: clamp(28px, calc(25px + 0.77vw), 36px); letter-spacing: -0.02em; line-height: 1.15; }
.about p { margin: 0 0 14px; color: var(--ink-2); max-width: 48ch; }
.about p:last-child { margin-bottom: 0; }

/* ---------- contact ---------- */
.meet .wrap { padding-top: 64px; padding-bottom: 92px; display: grid; grid-template-columns: 1fr; gap: 36px 56px; }
@media (min-width: 860px) { .meet .wrap { grid-template-columns: 0.8fr 1.2fr; align-items: start; } }
.meet h1, .meet h2 { margin: 0 0 16px; font-weight: 400; font-size: clamp(28px, calc(25px + 0.77vw), 36px); letter-spacing: -0.02em; line-height: 1.15; max-width: 18ch; text-wrap: balance; }
.meet-intro p { margin: 0; color: var(--ink-2); max-width: 40ch; }
.cf { position: relative; }
.cf .hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.cf-grid { display: grid; grid-template-columns: 1fr; gap: 20px 24px; }
@media (min-width: 640px) { .cf-grid { grid-template-columns: 1fr 1fr; } .cf-grid .full { grid-column: 1 / -1; } }
.cf label { display: block; }
.cf label span { display: block; margin-bottom: 8px; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.cf label span em { font-style: normal; text-transform: none; letter-spacing: 0; }
.cf input, .cf textarea { width: 100%; border: 1px solid var(--mortar); background: var(--cement); padding: 12px 14px; font: inherit; font-size: 15px; color: var(--ink); border-radius: 0; -webkit-appearance: none; }
.cf input:focus, .cf textarea:focus { outline: none; border-color: var(--ink); }
.cf textarea { resize: vertical; min-height: 120px; }
/* under 16px iOS Safari zooms the page in on focus and leaves it there */
@media (max-width: 860px) { .cf input, .cf textarea { font-size: 16px; } }
.cf ::placeholder { color: var(--ink-3); }
.cf-foot { margin-top: 28px; display: flex; flex-wrap: wrap; align-items: center; gap: 16px 24px; }
.cf .cta { color: var(--ink); background: none; cursor: pointer; font-family: inherit; }
.cf .cta:hover, .cf .cta:focus-visible { background: var(--ink); color: var(--plaster); }
.cf .cta:disabled { opacity: 0.5; cursor: default; }
.cf-note { margin: 0; font-size: 13px; color: var(--ink-2); }
.cf-note a { text-decoration: underline; text-underline-offset: 3px; }
.cf-sent { border: 1px solid var(--mortar); background: var(--cement); padding: 40px 28px; text-align: center; }
.cf-sent .big { margin: 0 0 8px; font-size: 24px; }
.cf-sent p { margin: 0; color: var(--ink-2); }

/* ---------- footer: the top bar again, closing the page ---------- */
.foot { background: var(--poured); color: rgba(255, 255, 255, 0.55); }
.foot .legal { padding-top: 16px; padding-bottom: 26px; display: flex; justify-content: space-between; align-items: baseline; gap: 10px 24px; flex-wrap: wrap; font-size: 12px; }
.foot a { color: inherit; }
/* the address line is the one place a thumb has to find a 12px link */
.foot .legal a { display: inline-block; padding: 7px 0; margin: -7px 0; }
