:root{
  --black:#151412;
  --black-2:#1B1A17;
  --cream:#F6F4EF;
  --cream-dim:rgba(246,244,239,.66);
  --green:#0F2C24;
  --line:rgba(246,244,239,.16);
  /* motion easings — read off the JDG/Aspen reference builds */
  --e-quart:cubic-bezier(.165,.84,.44,1);
  --e-expo:cubic-bezier(.19,1,.22,1);
  --e-wipe:cubic-bezier(.71,.07,.17,.91);
  /* JDG's band: no fixed content container, just a 4vw gutter on a full-width page */
  --gutter:4vw;
  /* relative to THIS stylesheet, not to the HTML — "assets/img/…" would resolve
     to assets/assets/img/… and 404 (silently: a 404 is not a failed request) */
  --logo:url("img/logo.png");
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  background:var(--black);
  color:var(--cream);
  font-family:'Archivo',Arial,sans-serif;
  font-size:16px;
  font-weight:400;
  line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
strong{font-weight:600;color:var(--cream)}
::selection{background:var(--cream);color:var(--black)}

/* No max-width cap. Capping it just swapped dead space on the right for margins on
   both sides — the band got narrower and the whole page read as shrunken. The fix for
   wide viewports is to make the CONTENT grow into the space (photos flex, text stays
   at a readable measure), not to fence the page in. */
.band{padding-left:var(--gutter);padding-right:var(--gutter)}

/* ---------- type roles ---------- */
/* JDG's signature: big statements at weight 400, sentence case, zero letter-spacing.
   Weight 700+ never appears above 50px. This is most of why it reads expensive
   rather than like a generic contractor site shouting in bold caps. */
.stmt{font-size:clamp(26px,4.2vw,60px);font-weight:400;line-height:1.06;letter-spacing:-.01em}
.stmt-sm{font-size:clamp(26px,3vw,40px);font-weight:400;line-height:1.12;letter-spacing:-.01em}
.lede{font-size:clamp(17px,1.35vw,20px);font-weight:400;line-height:1.6;color:var(--cream-dim)}
.eyebrow-none{}
.meta{font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-dim)}

/* text-link CTA — JDG has no filled buttons anywhere except the nav */
.tlink{
  display:inline-flex;align-items:center;gap:11px;
  font-size:15px;font-weight:500;padding-bottom:7px;
  border-bottom:1px solid rgba(246,244,239,.35);
  transition:gap .3s var(--e-expo),border-color .3s var(--e-expo);
}
.tlink svg{width:12px;height:12px;flex-shrink:0}
.tlink:hover{gap:18px;border-color:var(--cream)}
.tlink.dark{border-bottom-color:rgba(21,20,18,.3)}
.tlink.dark:hover{border-bottom-color:var(--black)}

/* ---------- reveal system ---------- */
.reveal{opacity:0;transform:translateY(24px);transition:opacity .9s var(--e-quart),transform .9s var(--e-quart)}
.reveal.in{opacity:1;transform:none}

/* ---------- masked line reveal ---------- */
.ml{--ml-dur:.75s}
.ml .l{display:block;overflow:hidden;padding-bottom:.06em;margin-bottom:-.06em}
.ml .l>i{
  display:block;font-style:normal;
  /* nowrap is load-bearing: a line that wraps inside the mask only reveals its
     first row. Lines are hand-broken and the clamp mins are tuned to fit 320px. */
  white-space:nowrap;
  transform:translateY(110%);
  transition:transform var(--ml-dur) var(--e-quart);
}
.ml.in .l>i{transform:none}
.ml .l:nth-child(2)>i{transition-delay:.1s}
.ml .l:nth-child(3)>i{transition-delay:.2s}
.ml .l:nth-child(4)>i{transition-delay:.3s}

/* ---------- clip-path image wipe ---------- */
.wipe{clip-path:inset(0 0 0 100%);transition:clip-path 1.1s var(--e-wipe)}
.wipe.in{clip-path:inset(0 0 0 0)}

.d1{transition-delay:.1s}
.d2{transition-delay:.2s}
.d3{transition-delay:.3s}

/* ---------- nav ---------- */
header{
  position:fixed;inset:0 0 auto 0;z-index:50;
  transition:background .4s var(--e-expo),border-color .3s var(--e-expo),color .5s var(--e-expo);
  border-bottom:1px solid transparent;
}
/* Every section under the fixed nav is a photo, and the hero's is a bright forest
   canopy right where the links sit. Without this wash the nav is unreadable at
   scroll 0. Fades out once the solid scrolled state takes over. */
header::before{
  content:'';position:absolute;inset:0 0 -48px 0;z-index:-1;pointer-events:none;
  background:linear-gradient(to bottom,rgba(15,14,12,.72) 0%,rgba(15,14,12,0) 100%);
  transition:opacity .4s var(--e-expo);
}
header.scrolled::before{opacity:0}
header.scrolled{background:rgba(21,20,18,.92);backdrop-filter:blur(12px);border-color:var(--line)}
body.inv header::before{opacity:0}

/* ---------- theme inversion ---------- */
/* Chrome flips to dark-on-cream while a cream section sits under the fixed nav.
   Split timing (bg 400ms / text 500ms / chrome 300ms) is what makes this read as
   designed rather than as a class toggle. */
body.inv header{color:var(--black)}
body.inv header.scrolled{background:rgba(246,244,239,.92);border-color:rgba(21,20,18,.14)}
body.inv header .logomark{filter:invert(1)}
body.inv .wordmark span{color:rgba(21,20,18,.58)}
body.inv .nav-links a{color:rgba(21,20,18,.58)}
body.inv .nav-links a:hover{color:var(--black)}
body.inv .nav-cta{background:var(--black);color:var(--cream)}
body.inv .util a{background:rgba(246,244,239,.9);border-color:rgba(21,20,18,.14);color:var(--black)}
body.inv .util a:hover{background:var(--black);color:var(--cream)}

.nav{display:flex;align-items:center;justify-content:space-between;padding-top:18px;padding-bottom:18px}
/* No wordmark — the logo already reads "Yates Construction & Renovation", so setting
   the name in type beside it said it twice. Logo carries the identity on its own. */
.wordmark{display:flex;align-items:center;flex-shrink:0}
.logomark{display:inline-block;width:124px;aspect-ratio:480/355;background:var(--logo) center/contain no-repeat;flex-shrink:0;transition:filter .4s var(--e-expo)}
.logomark.lg{width:178px}
.nav-links{display:flex;gap:30px;font-size:14px;font-weight:400}
/* Mockup header treatment: animated underline on hover, green indicator on the
   active page (aria-current). Ported site-wide, logo kept. */
.nav-links a{position:relative;padding:4px 0;color:var(--cream-dim);transition:color .5s var(--e-expo)}
.nav-links a::after{content:"";position:absolute;left:0;bottom:-1px;height:1px;width:0;background:var(--cream);transition:width .4s var(--e-quart)}
.nav-links a:hover{color:var(--cream)}
.nav-links a:hover::after{width:100%}
.nav-links a[aria-current="page"]{color:var(--cream)}
.nav-links a[aria-current="page"]::after{width:100%;height:2px;background:#7FA894}
/* On cream sections under the nav (body.inv) keep both underlines visible */
body.inv .nav-links a::after{background:var(--black)}
body.inv .nav-links a[aria-current="page"]::after{background:var(--green)}
.nav-cta{
  background:var(--cream);color:var(--black);
  font-size:13px;font-weight:500;
  padding:12px 20px;display:inline-flex;align-items:center;gap:8px;
  transition:transform .25s ease,background .4s var(--e-expo),color .5s var(--e-expo);
}
.nav-cta:hover{transform:translateY(-2px)}
.nav-cta svg{width:11px;height:11px}

/* ---------- persistent utility bar ---------- */
.util{position:fixed;right:20px;bottom:20px;z-index:50;display:flex;gap:2px}
.util a{
  background:rgba(21,20,18,.9);backdrop-filter:blur(10px);
  border:1px solid var(--line);
  color:var(--cream);font-size:12px;font-weight:500;
  padding:12px 17px;display:inline-flex;align-items:center;gap:9px;
  transition:background .4s var(--e-expo),color .5s var(--e-expo),border-color .3s var(--e-expo);
}
.util a:hover{background:var(--green)}
.util svg{width:13px;height:13px;opacity:.85}

/* ---------- hero ---------- */
.hero{position:relative;height:100vh;min-height:620px;display:flex;align-items:flex-end;overflow:hidden}
.hero-img{position:absolute;inset:-14% 0;will-change:transform}
/* Ken-burns settle. The reference runs 1.4 -> 1.0, which visibly softens a
   full-bleed photo; 1.07 keeps it sharp and still gives the frame life.
   Scale sits on the img, scroll parallax on the wrapper — no transform conflict. */
.hero-img img{
  width:100%;height:100%;object-fit:cover;object-position:58% 46%;
  transform:scale(1.07);
  transition:transform 2s var(--e-expo);
}
body.ready .hero-img img{transform:scale(1)}
/* JDG leans on one flat scrim, but its hero is a dark interior crop. Ours is a forest
   with a bright canopy exactly where the fixed nav sits, so it needs a top wash too —
   otherwise the nav links disappear into the trees. */
.hero-scrim{position:absolute;inset:0;background:rgba(15,14,12,.42)}
.hero-scrim.grad{background:
  linear-gradient(to bottom,rgba(15,14,12,.62) 0%,rgba(15,14,12,0) 26%),
  linear-gradient(to top,rgba(15,14,12,.74) 0%,rgba(15,14,12,.10) 58%)}
.hero-inner{position:relative;width:100%;padding-bottom:104px}
.hero h1{font-size:clamp(33px,5.6vw,82px);font-weight:400;line-height:1.02;letter-spacing:-.015em;max-width:15ch}
.hero .sub{margin-top:26px;max-width:46ch}
.hero .acts{margin-top:40px;display:flex;gap:34px;flex-wrap:wrap}

/* ---------- intro ---------- */
/* Asymmetric 57/43 — JDG never splits 50/50. Copy block is vertically centred and
   its measure is set by a % max-width, not margin:auto. */
/* 52/48 rather than 57/43 — still asymmetric per the reference, but the feature
   photo is landscape now and needs the width to stay the "big one" in this section */
.intro{display:grid;grid-template-columns:52fr 48fr;gap:100px;padding-top:180px;padding-bottom:180px;align-items:center}
.intro .copy{max-width:80%}
.intro .copy .stmt-sm{margin-bottom:34px}
.intro .copy p+p{margin-top:22px}
.intro .copy .tlink{margin-top:40px}
/* one big photo + one staggered smaller one. JDG never uses a tidy row of three. */
.intro .shots{position:relative;display:grid;grid-template-columns:1fr;gap:0}
/* 4:3, not 4:5 — the source is a 3:2 landscape and a portrait frame would crop
   away the covered porch, which is the whole subject of the shot */
.intro .shot-a{aspect-ratio:4/3;overflow:hidden}
.intro .shot-a img{width:100%;height:100%;object-fit:cover;object-position:50% 42%}
/* clips the feature shot's corner only — at 60%/-118px it covered ~40% of it,
   including the garage wing, which defeats the point of the photo */
.intro .shot-b{
  position:absolute;left:-172px;bottom:-70px;width:46%;aspect-ratio:4/3;overflow:hidden;
  border:8px solid var(--black);
}
.intro .shot-b img{width:100%;height:100%;object-fit:cover}

/* ---------- statement band ---------- */
/* JDG's showreel: full-bleed photo, ONE flat scrim, big light heading bottom-left
   in a ~54% column. Not a centred banner, never on flat colour. */
.band-stmt{position:relative;height:78vh;min-height:460px;display:flex;align-items:flex-end;overflow:hidden}
.band-stmt .bg{position:absolute;inset:-10% 0;will-change:transform}
/* biased up: the source's lower third is scaffolding and a blue tarp */
.band-stmt .bg img{width:100%;height:100%;object-fit:cover;object-position:50% 26%}
/* Left-biased, not a full bottom wash. The old stack hit ~0.85 across the whole
   bottom, which flattened the photo no matter how bright the source was. This
   darkens only the left third where the copy sits and lets the building stay lit. */
.band-stmt .scrim{position:absolute;inset:0;background:
  linear-gradient(to bottom,rgba(15,14,12,.5) 0%,rgba(15,14,12,0) 26%),
  linear-gradient(102deg,rgba(15,14,12,.82) 0%,rgba(15,14,12,.46) 40%,rgba(15,14,12,.08) 76%)}
/* px/% not ch — ch resolves against THIS element's 16px font, so `60ch` is ~480px
   while the 60px heading inside needs ~540px of nowrap. JDG uses a 776px column. */
.band-stmt .inner{position:relative;width:100%;padding-bottom:82px;max-width:min(940px,66%)}
.band-stmt .lede{margin-top:24px;max-width:52ch}

/* ---------- projects rail ---------- */
.proj-head{padding-top:170px;padding-bottom:60px;display:flex;justify-content:space-between;align-items:flex-end;gap:40px;flex-wrap:wrap}
/* Portrait cards at JDG's scale — NOT full-viewport zoomed panels. Whole buildings,
   several at once. The reference pins these as a horizontal rail, but it has five;
   with three the rail travels ~70px and the pin is theatre. Static grid until
   Campbell confirms which photos belong to the other two named projects. */
.proj-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;padding-bottom:180px}
.card{position:relative;aspect-ratio:470/606;overflow:hidden}
/* Project images are stills — no clip wipe, no hover scale. The photos are the
   work; the "View project" line carries the affordance instead. */
.card .ph{position:absolute;inset:0;overflow:hidden}
.card .ph img{width:100%;height:100%;object-fit:cover}
.card .veil{position:absolute;inset:0;background:linear-gradient(to top,rgba(15,14,12,.78) 0%,rgba(15,14,12,.05) 58%)}
.card .cap{position:absolute;left:30px;right:30px;bottom:28px}
.card .cap h3{font-size:clamp(21px,1.7vw,27px);font-weight:400;line-height:1.14;letter-spacing:-.01em}
.card .cap span{display:block;margin-top:9px}

/* Expandable selected-projects gallery (homepage only).
   Ported from a framer-motion component to pure CSS: a flex row where the
   hovered panel grows and its neighbours shrink. Click still navigates to the
   project page — the cards stay <a> links. */
.proj-grid.expand{display:flex;gap:14px;height:clamp(440px,64vh,640px);padding-bottom:0;margin-bottom:180px}
.proj-grid.expand .card{flex:1 1 0;min-width:0;height:100%;aspect-ratio:auto;transition:flex .55s cubic-bezier(.5,0,.2,1)}
.proj-grid.expand:hover .card:not(:hover),
.proj-grid.expand:focus-within .card:not(:focus-visible){flex:.62 1 0}
.proj-grid.expand .card:hover,
.proj-grid.expand .card:focus-visible{flex:2.4 1 0}
/* Darken the neighbours (image only) so the focused panel reads first. */
.proj-grid.expand .card .ph::after{content:"";position:absolute;inset:0;background:#0f0e0c;opacity:0;transition:opacity .4s;pointer-events:none}
.proj-grid.expand:hover .card:not(:hover) .ph::after{opacity:.34}
/* Fade the collapsed captions to a single clean line of imagery. */
.proj-grid.expand .card .cap{transition:opacity .4s}
.proj-grid.expand:hover .card:not(:hover) .cap{opacity:0}

/* ---------- services ---------- */
/* JDG: one tall photo + a text grid. No photo cards, no icons, no borders. */
.svc-wrap{display:grid;grid-template-columns:33fr 67fr;gap:100px;padding-top:180px;padding-bottom:180px;align-items:start}
.svc-photo{aspect-ratio:2/3;overflow:hidden;position:relative}
.svc-photo img{width:100%;height:100%;object-fit:cover}
.svc-head{margin-bottom:56px}
.svc-head .lede{margin-top:20px;max-width:52ch}
.svc-list{display:grid;grid-template-columns:1fr 1fr;gap:52px 60px}
.svc-item h3{font-size:20px;font-weight:500;margin-bottom:11px;letter-spacing:-.005em}
.svc-item p{font-size:15.5px;color:var(--cream-dim);line-height:1.62;max-width:34ch}

/* ---------- testimonial ---------- */
/* The one cream room on a dark page. Scrolling it under the nav flips the chrome.
   Centred — the only centred block on the site, which is what makes it land. */
.testimonial{padding-top:170px;padding-bottom:170px;background:var(--cream);color:var(--black);text-align:center}
.testimonial .inner{max-width:min(1080px,84%);margin:0 auto}
.testimonial blockquote{font-size:clamp(24px,3.1vw,44px);font-weight:400;line-height:1.22;letter-spacing:-.015em;max-width:100%}
.testimonial strong{color:var(--black)}
.testimonial cite{display:block;margin-top:40px;font-style:normal;font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--green)}
.testimonial ::selection{background:var(--black);color:var(--cream)}

/* ---------- closing cta ---------- */
.statement{position:relative;height:88vh;min-height:520px;display:flex;align-items:flex-end;overflow:hidden}
.statement .bg{position:absolute;inset:-10% 0;will-change:transform}
.statement .bg img{width:100%;height:100%;object-fit:cover}
.statement .scrim{position:absolute;inset:0;background:rgba(15,14,12,.5)}
.statement .inner{position:relative;width:100%;padding-bottom:96px;max-width:min(880px,64%)}
.statement .tlink{margin-top:40px}

/* ---------- footer ---------- */
footer{border-top:1px solid var(--line);padding-top:84px;padding-bottom:130px;background:var(--black)}
.foot{display:grid;grid-template-columns:2fr 1fr 1fr;gap:56px}
.foot .wm b{font-weight:700;font-size:21px}
.foot .wm p{margin-top:16px;color:var(--cream-dim);max-width:34ch;font-size:15px}
.foot h4{font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-dim);margin-bottom:18px}
.foot ul{list-style:none}
.foot li{margin-bottom:10px;font-size:15px}
.foot a:hover{text-decoration:underline;text-underline-offset:4px}
.legal{margin-top:64px;padding-top:28px;border-top:1px solid var(--line);display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;font-size:12.5px;color:var(--cream-dim)}

/* ---------- responsive ---------- */
@media(max-width:1060px){
  :root{--gutter:24px}
  .nav{padding-top:18px;padding-bottom:18px;gap:12px}
  .nav-links{display:none}
  .wordmark span{display:none}
  .nav-cta{white-space:nowrap;font-size:12px;padding:11px 15px}
  .intro{grid-template-columns:1fr;gap:0;padding-top:100px;padding-bottom:100px}
  .intro .copy{max-width:100%;order:1}
  .intro .shots{order:2;margin-top:64px}
  .intro .shot-a{aspect-ratio:4/3}
  .intro .shot-b{display:none}
  .svc-wrap{grid-template-columns:1fr;gap:56px;padding-top:100px;padding-bottom:100px}
  .svc-photo{aspect-ratio:3/2}
  .svc-list{grid-template-columns:1fr;gap:40px}
  .proj-head{padding-top:100px}
  .proj-grid{grid-template-columns:1fr;gap:16px;padding-bottom:100px}
  /* No hover on touch — revert the expandable row to the stacked grid. */
  .proj-grid.expand{display:grid;grid-template-columns:1fr;height:auto;gap:16px;padding-bottom:0;margin-bottom:100px}
  .proj-grid.expand .card{height:auto;aspect-ratio:4/3.4}
  .proj-grid.expand:hover .card:not(:hover) .cap{opacity:1}
  .proj-grid.expand:hover .card:not(:hover) .ph::after{opacity:0}
  .card{aspect-ratio:4/3.4}
  .testimonial{padding-top:110px;padding-bottom:110px}
  .testimonial .inner,.testimonial blockquote{max-width:100%}
  footer{padding-top:64px;padding-bottom:140px}
  .foot{grid-template-columns:1fr;gap:40px}
  .hero-inner{padding-bottom:88px}
  /* The phone crop of the hero photo puts a sunlit shrub directly behind the sub-line,
     where the desktop crop had dark siding. Deepen the bottom wash on small screens only
     so the 17px sub keeps its contrast; the headline and the desktop scrim are untouched. */
  .hero-scrim.grad{background:
    linear-gradient(to bottom,rgba(15,14,12,.62) 0%,rgba(15,14,12,0) 26%),
    linear-gradient(to top,rgba(15,14,12,.80) 0%,rgba(15,14,12,.30) 62%)}
  /* the desktop % caps become ~210px on a phone and strangle the nowrap headings */
  .band-stmt .inner,.statement .inner,.testimonial .inner{max-width:100%}
  .band-stmt{height:auto;min-height:0;padding-top:150px}
  .band-stmt .inner{padding-bottom:110px}
  .statement .inner{padding-bottom:88px}
}
@media(max-width:560px){
  .logomark{width:44px}
  .wordmark{gap:10px}
  .wordmark b{font-size:17px}
  .nav-cta{font-size:10px;padding:10px 12px}
  .nav-cta svg{width:9px;height:9px}
  .hero .acts{gap:20px}
}

/* ================= INNER PAGES ================= */

/* ---------- page header band ---------- */
/* Same grammar as the homepage statement band, shorter. Photo + flat-ish scrim,
   H1 bottom-left. Keeps every page opening on the same axis. */
.page-hero{position:relative;height:62vh;min-height:400px;display:flex;align-items:flex-end;overflow:hidden}
.page-hero .bg{position:absolute;inset:-10% 0;will-change:transform}
.page-hero .bg img{width:100%;height:100%;object-fit:cover}
.page-hero .scrim{position:absolute;inset:0;background:
  linear-gradient(to bottom,rgba(15,14,12,.6) 0%,rgba(15,14,12,.3) 24%),
  linear-gradient(to top,rgba(15,14,12,.72) 0%,rgba(15,14,12,.3) 55%)}
.page-hero .inner{position:relative;width:100%;padding-bottom:74px;max-width:min(900px,66%)}
.page-hero h1{font-size:clamp(30px,4.6vw,64px);font-weight:400;line-height:1.04;letter-spacing:-.015em}
.page-hero .lede{margin-top:20px;max-width:52ch}
/* flat variant for pages with no worthwhile photo */
.page-hero.flat{height:auto;min-height:0;padding-top:210px;background:var(--black)}
.page-hero.flat .inner{padding-bottom:70px}

/* ---------- about: essay ---------- */
.essay{display:grid;grid-template-columns:57fr 43fr;gap:100px;padding-top:150px;padding-bottom:170px;align-items:start}
.essay .body p{font-size:17px;line-height:1.72;color:var(--cream-dim);max-width:62ch}
.essay .body p+p{margin-top:26px}
.essay .body p:first-child{font-size:clamp(19px,1.5vw,23px);line-height:1.55;color:var(--cream)}
.essay .sig{margin-top:40px;font-size:15px;color:var(--cream);font-weight:500}
.essay .portrait{position:sticky;top:120px}
/* the portrait source is landscape 3:2 — crop to 4:5 and hold Campbell in frame */
.essay .portrait .shot{aspect-ratio:4/5;overflow:hidden}
.essay .portrait img{width:100%;height:100%;object-fit:cover;object-position:58% 40%}
.essay .portrait figcaption{margin-top:18px}
/* our-team: each bio reuses the essay two-column rhythm, so no new layout idiom.
   The name/role pair uses the existing .stmt-sm and .meta type roles; .meta has to be
   re-asserted here because `.essay .body p` outranks a lone class on the same element.
   The lede treatment moves off :first-child (an h2 now holds that slot) onto the first
   paragraph after the role line, with the same values it had on about.html. */
.essay .body .meta{font-size:12px;margin-top:14px;max-width:none}
.essay .body h2+.meta+p{margin-top:30px;font-size:clamp(19px,1.5vw,23px);line-height:1.55;color:var(--cream)}
.essay+.essay{padding-top:110px;border-top:1px solid var(--line)}

/* ---------- about: family inset ---------- */
/* Photo flexes up to a sane cap, pull-quote is capped at its own measure, and the
   pair is held together instead of being stretched across an fr grid — the old
   38fr/62fr put a 400px photo in a 500px column and a ~350px line in an 800px one. */
/* NB: never size these tracks in `ch` — ch resolves against the GRID's 16px font,
   not the 28px pull-quote inside, so `22ch` crushed the text to ~200px. Use px.
   `auto` + justify-content:start packs the pair left instead of stranding a
   capped photo inside an fr column. */
.family{display:grid;grid-template-columns:auto minmax(0,460px);justify-content:start;gap:clamp(48px,5vw,90px);align-items:center;padding-bottom:170px}
.family .shot{overflow:hidden;aspect-ratio:3/4}
.family .shot img{width:100%;height:100%;object-fit:cover}
.family .shot-wrap{width:clamp(300px,40vw,560px)}
.family figcaption{margin-top:18px}
.family .note{font-size:clamp(19px,2vw,30px);font-weight:400;line-height:1.4;letter-spacing:-.015em}

/* ---------- contact: image ---------- */
.contact-hero{position:relative;height:52vh;min-height:340px;overflow:hidden;display:flex;align-items:flex-end}
.contact-hero .bg{position:absolute;inset:-10% 0;will-change:transform}
.contact-hero .bg img{width:100%;height:100%;object-fit:cover;object-position:50% 46%}
.contact-hero .scrim{position:absolute;inset:0;background:
  linear-gradient(to bottom,rgba(15,14,12,.6) 0%,rgba(15,14,12,.22) 30%),
  linear-gradient(to top,rgba(15,14,12,.7) 0%,rgba(15,14,12,.2) 60%)}
.contact-hero .inner{position:relative;width:100%;padding-bottom:56px}

/* ---------- services page ---------- */
/* Alternating asymmetric rows. Never 50/50, and the photo swaps sides so the page
   has a rhythm instead of six identical stripes. */
/* Alternating edge-bleed bands. The photo runs to the viewport edge and absorbs ALL
   extra width; only the text side takes a gutter. Text is capped in px at a readable
   measure (never ch — ch resolves against the grid's font, not the child's).
   At 1920 this puts the photo near 1200px instead of stranding 500px of dead space. */
.svc-block{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,clamp(360px,32vw,560px));
  gap:clamp(40px,4vw,84px);
  align-items:center;
  padding:clamp(70px,7vw,120px) var(--gutter) clamp(70px,7vw,120px) 0;
  border-top:1px solid var(--line);
}
.svc-block:first-of-type{border-top:0}
/* flip must swap the TRACKS too, not just the order — otherwise the text lands in the
   1fr track (a 1280px measure) and the photo gets squeezed into the fixed one. */
.svc-block.flip{
  grid-template-columns:minmax(0,clamp(360px,32vw,560px)) minmax(0,1fr);
  padding-right:0;padding-left:var(--gutter);
}
.svc-block.flip .shot{order:2}
.svc-block .shot{aspect-ratio:16/10;overflow:hidden}
.svc-block .shot img{width:100%;height:100%;object-fit:cover}
.svc-block h2{font-size:clamp(24px,2.6vw,38px);font-weight:400;letter-spacing:-.015em;line-height:1.1}
.svc-block .tag{margin-top:12px;font-size:15px;color:var(--green);font-weight:500}
body .svc-block .tag{color:#7FA894}
/* the column caps the measure now — a 56ch cap in a 46ch column just stranded space */
.svc-block .txt p{margin-top:24px;font-size:16px;line-height:1.7;color:var(--cream-dim)}

/* ---------- projects page ---------- */
.proj-list{display:grid;grid-template-columns:repeat(3,1fr);gap:26px;padding-top:110px;padding-bottom:170px}
.proj-list .card{aspect-ratio:470/560}
.proj-list .card .cap h3{font-size:clamp(19px,1.5vw,24px)}
.proj-list .card .desc{
  margin-top:12px;font-size:14px;line-height:1.6;color:rgba(246,244,239,.82);
  max-height:0;opacity:0;overflow:hidden;
  transition:max-height .55s var(--e-expo),opacity .4s var(--e-expo),margin-top .55s var(--e-expo);
}
.proj-list .card:hover .desc,.proj-list .card:focus-within .desc{max-height:15em;opacity:1}
.proj-list .card .veil{background:linear-gradient(to top,rgba(15,14,12,.9) 0%,rgba(15,14,12,.35) 45%,rgba(15,14,12,.05) 75%)}

/* ---------- project detail page ---------- */
.page-hero .meta{margin-bottom:18px}
.proj-detail{padding-top:120px;padding-bottom:80px;max-width:min(820px,72%)}
.proj-detail .detail-copy .lede{font-size:clamp(18px,1.5vw,23px);line-height:1.6;color:var(--cream)}
.proj-detail .tlink{margin-top:44px}
.inline-link{border-bottom:1px solid rgba(246,244,239,.35);transition:border-color .3s var(--e-expo)}
.inline-link:hover{border-bottom-color:var(--cream)}

/* Mixed-size gallery — a tidy uniform grid is the thing JDG never does.
   Sizing is by ROW SPAN against a fixed row height, not aspect-ratio: with
   aspect-ratio, a 4-col item and a 2-col item in the same row resolve to
   different heights and the grid goes ragged with holes. Fixed rows + spans
   pack exactly. The 8-item cycle below always sums to 6 columns:
     1: [ ---- big ---- ][ a ][ b ]   (big spans 2 rows; a+b stack to match)
     2: [ --- 3 --- ][ --- 3 --- ]
     3: [ 2 ][ 2 ][ 2 ]                                                     */
.gallery{
  display:grid;grid-template-columns:repeat(6,1fr);
  grid-auto-rows:clamp(170px,18.5vw,272px);
  grid-auto-flow:dense;      /* backfill holes when a project's count is odd */
  gap:22px;padding-bottom:140px;
}
.gal-item{overflow:hidden;grid-column:span 2;grid-row:span 1}
/* stills — no wipe, no hover scale. Project photography does not perform. */
.gal-item img{width:100%;height:100%;object-fit:cover}
.gal-item:nth-child(8n+1){grid-column:span 4;grid-row:span 2}
.gal-item:nth-child(8n+4){grid-column:span 3}
.gal-item:nth-child(8n+5){grid-column:span 3}

/* prev / all / next */
.proj-nav{display:grid;grid-template-columns:1fr auto 1fr;gap:30px;align-items:center;
  padding-top:56px;padding-bottom:130px;border-top:1px solid var(--line)}
.pn{display:flex;flex-direction:column;gap:9px;transition:opacity .3s var(--e-expo)}
.pn:hover{opacity:.62}
.pn-name{font-size:clamp(18px,1.7vw,26px);font-weight:400;letter-spacing:-.01em;line-height:1.15}
.pn.next{text-align:right;align-items:flex-end}
.pn.all{align-items:center}
.pn.all .meta{border-bottom:1px solid var(--line);padding-bottom:6px}
.card-go{
  display:inline-flex;align-items:center;gap:8px;margin-top:14px;
  font-size:13px;font-weight:500;color:var(--cream);
  opacity:0;transform:translateY(6px);
  transition:opacity .4s var(--e-expo),transform .4s var(--e-expo),gap .3s var(--e-expo);
}
.card-go svg{width:10px;height:10px}
.card:hover .card-go,.card:focus-visible .card-go{opacity:1;transform:none}
.card:hover .card-go{gap:14px}

/* ---------- contact page ---------- */
.contact-wrap{display:grid;grid-template-columns:40fr 60fr;gap:100px;padding-top:150px;padding-bottom:170px;align-items:start}
.contact-det dt{font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-dim);margin-bottom:8px}
.contact-det dd{font-size:18px;margin-bottom:34px}
.contact-det dd a:hover{text-decoration:underline;text-underline-offset:4px}
.contact-social{display:flex;gap:12px;margin-top:8px}
.contact-social a{
  width:42px;height:42px;border:1px solid var(--line);display:inline-flex;align-items:center;justify-content:center;
  transition:background .3s var(--e-expo),border-color .3s var(--e-expo);
}
.contact-social a:hover{background:var(--cream);border-color:var(--cream);color:var(--black)}
.contact-social svg{width:17px;height:17px}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.field{margin-bottom:22px}
.field label{display:block;font-size:12px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--cream-dim);margin-bottom:9px}
.field input,.field textarea{
  width:100%;background:transparent;border:0;border-bottom:1px solid var(--line);
  color:var(--cream);font-family:inherit;font-size:16px;padding:11px 0;
  transition:border-color .3s var(--e-expo);
}
.field textarea{resize:vertical;min-height:120px}
.field input:focus,.field textarea:focus{outline:0;border-bottom-color:var(--cream)}
.field input:focus-visible,.field textarea:focus-visible{outline:0}
.form-submit{
  margin-top:14px;background:var(--cream);color:var(--black);border:0;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:500;padding:15px 30px;
  display:inline-flex;align-items:center;gap:9px;
  transition:transform .25s ease,opacity .25s ease;
}
.form-submit:hover{transform:translateY(-2px)}
.form-submit svg{width:11px;height:11px}
.form-note{margin-top:20px;font-size:13.5px;color:var(--cream-dim)}
.form-submit:disabled{opacity:.55;cursor:default;transform:none}
/* honeypot — off-screen rather than display:none, which some bots skip */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.map-band{aspect-ratio:21/6;min-height:280px;background:var(--black-2);border-top:1px solid var(--line)}
.map-band iframe{width:100%;height:100%;border:0;display:block;filter:grayscale(1) invert(.92) contrast(.85)}

@media(max-width:1060px){
  .page-hero{height:auto;min-height:0;padding-top:150px}
  .page-hero .inner{max-width:100%;padding-bottom:70px}
  .page-hero.flat{padding-top:150px}
  .essay{grid-template-columns:1fr;gap:56px;padding-top:80px;padding-bottom:100px}
  .essay+.essay{padding-top:64px}
  .essay .portrait{position:static;max-width:340px}
  .family{grid-template-columns:1fr;gap:40px;padding-bottom:90px}
  .family .shot{max-width:280px}
  .contact-hero{height:auto;min-height:0;padding-top:150px}
  .contact-hero .inner{padding-bottom:50px}
  /* single column on touch — photo still bleeds full width, text takes the gutter */
  .svc-block,.svc-block.flip{grid-template-columns:1fr;gap:32px;padding:70px 0}
  .svc-block.flip .shot{order:0}
  .svc-block .shot{aspect-ratio:4/3}
  .svc-block .txt{padding-left:var(--gutter);padding-right:var(--gutter)}
  .proj-list{grid-template-columns:1fr;gap:16px;padding-top:70px;padding-bottom:100px}
  .proj-list .card{aspect-ratio:4/3.4}
  .proj-list .card .desc{max-height:15em;opacity:1}
  .contact-wrap{grid-template-columns:1fr;gap:56px;padding-top:80px;padding-bottom:100px}
  .form-row{grid-template-columns:1fr;gap:0}
  .map-band{aspect-ratio:4/3;min-height:0}
  .proj-detail{max-width:100%;padding-top:70px;padding-bottom:50px}
  .gallery{grid-template-columns:1fr;grid-auto-rows:auto;gap:14px;padding-bottom:80px}
  .gal-item,.gal-item:nth-child(8n+1),.gal-item:nth-child(8n+4),.gal-item:nth-child(8n+5){
    grid-column:span 1;grid-row:span 1;aspect-ratio:4/3}
  .proj-nav{grid-template-columns:1fr;gap:32px;padding-bottom:90px}
  .pn.next{text-align:left;align-items:flex-start}
  .pn.all{align-items:flex-start}
  .card-go{opacity:1;transform:none}
}

/* ---------- reduced motion ---------- */
/* MUST be the last block in the sheet. A media query adds no specificity, so these
   overrides only win on source order. */
@media(prefers-reduced-motion:reduce){
  .reveal{opacity:1!important;transform:none!important;transition:none!important}
  .ml .l>i{transform:none!important;transition:none!important}
  .wipe{clip-path:none!important;transition:none!important}
  .hero-img,.hero-img img,.band-stmt .bg,.statement .bg,.card .ph,.card .ph img{transform:none!important;transition:none!important}
  .d1,.d2,.d3{transition-delay:0s!important}
  html{scroll-behavior:auto}
}
