/* ==========================================================================
   JBM Patios & Landscapes
   Layout Creative — 2026
   --------------------------------------------------------------------------
   1. Fonts
   2. Tokens
   3. Base
   4. Layout primitives
   5. Typography
   6. Header & navigation
   7. Buttons & links
   8. The plan mark (logo motif)
   9. Annotated photography
  10. Components
  11. Footer
  12. Motion
  13. Page furniture (page heads, process, sticky columns)
  14. Before & after
  15. Gallery & lightbox
  16. Service detail
  17. People & reviews
  18. On a dark ground
  19. Responsive
   ========================================================================== */

/* 1. FONTS ---------------------------------------------------------------- */

@font-face{
  font-family:'Fraunces';
  src:url('../fonts/fraunces.woff2') format('woff2');
  font-weight:100 900; font-display:swap;
}
@font-face{
  font-family:'Figtree';
  src:url('../fonts/figtree.woff2') format('woff2');
  font-weight:300 800; font-display:swap;
}
@font-face{
  font-family:'SpaceMono';
  src:url('../fonts/spacemono.woff2') format('woff2');
  font-weight:400; font-display:swap;
}
@font-face{
  font-family:'SpaceMono';
  src:url('../fonts/spacemono-bold.woff2') format('woff2');
  font-weight:700; font-display:swap;
}

/* 2. TOKENS --------------------------------------------------------------- */

:root{
  /* Text greens — darker tones of the logo hue, chosen to pass contrast.
     Pine carries 4.98:1 on paper; the logo's own #209038 only manages 3.87. */
  --pine:#2C7A45;
  --pine-deep:#1F5C33;

  /* Logo-true colours. Accent use only — none of these pass as small text. */
  --leaf:#80C828;
  --amber:#F89838;
  --amber-text:#8F4C06;   /* the same hue, dark enough to read at 11px */
  --logo-green:#209038;

  /* Ground */
  --ink:#26241F;
  --ink-soft:#4A463D;
  --ink-mute:#635D52;
  --paper:#FAF8F3;
  --stone:#E8E3D8;
  --stone-deep:#DAD3C4;

  --rule:rgba(38,36,31,.13);
  --rule-strong:rgba(38,36,31,.28);
  --rule-dark:rgba(250,248,243,.18);

  --display:'Fraunces',Georgia,'Times New Roman',serif;
  --body:'Figtree',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --mono:'SpaceMono',ui-monospace,Menlo,Consolas,monospace;

  /* Deliberately uneven. Sections pick from this rather than all sharing one. */
  --sp-xs:clamp(28px,4vw,44px);
  --sp-s:clamp(36px,5vw,58px);
  --sp-m:clamp(48px,6.4vw,84px);
  --sp-l:clamp(60px,8.4vw,112px);
  --sp-xl:clamp(80px,11vw,150px);

  --gutter:clamp(20px,5vw,64px);
  --maxw:1280px;
  --measure:62ch;

  --ease:cubic-bezier(.16,1,.3,1);
  --ease-soft:cubic-bezier(.4,0,.2,1);

  --sbw:0px;   /* scrollbar width, measured at runtime */
}

/* 3. BASE ----------------------------------------------------------------- */

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  font-size:17px;
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
:focus-visible{outline:2px solid var(--pine);outline-offset:3px;border-radius:1px}
::selection{background:var(--leaf);color:var(--ink)}

/* 4. LAYOUT PRIMITIVES ---------------------------------------------------- */

/* The container everything measures against. */
.shell{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}

/* Break out of the shell. The site's main tool for avoiding a single column
   of evenly-stacked boxes.
   --sbw is the scrollbar width, set by jbm.js. Without it, 100vw includes the
   scrollbar and every bleed section pushes the page sideways. */
.bleed{width:calc(100vw - var(--sbw));margin-inline:calc(50% - 50vw + var(--sbw) / 2)}
.bleed-r{margin-right:calc(50% - 50vw + var(--sbw) / 2)}
.bleed-l{margin-left:calc(50% - 50vw + var(--sbw) / 2)}

/* Asymmetric editorial grid. Nothing here is a 6/6 split. */
.grid{display:grid;gap:clamp(24px,4vw,56px)}
.g-7-5{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
.g-5-7{grid-template-columns:minmax(0,5fr) minmax(0,7fr)}
.g-8-4{grid-template-columns:minmax(0,8fr) minmax(0,4fr)}
.g-4-8{grid-template-columns:minmax(0,4fr) minmax(0,8fr)}
.g-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g-2{grid-template-columns:repeat(2,minmax(0,1fr))}

.section{padding-block:var(--sp-m)}
.section--tight{padding-block:var(--sp-s)}
.section--tall{padding-block:var(--sp-l)}
.section--ink{background:var(--ink);color:var(--paper)}
.section--stone{background:var(--stone)}

.section--ink .lbl{color:var(--leaf)}
.section--ink .lede,.section--ink p{color:rgba(250,248,243,.82)}
.section--ink a{color:var(--paper)}

.stack>*+*{margin-top:1.1em}
.measure{max-width:var(--measure)}

/* 5. TYPOGRAPHY ----------------------------------------------------------- */

h1,h2,h3,h4{
  font-family:var(--display);
  font-weight:600;
  margin:0;
  letter-spacing:-.022em;
  line-height:1.02;
  font-variation-settings:'opsz' 144,'SOFT' 24;
}
/* Big scale jump, then a gap. Avoids the flat mid-range that makes
   generated pages feel samey. */
.d1{font-size:clamp(46px,7.4vw,104px)}
.d2{font-size:clamp(34px,4.6vw,64px)}
.d3{font-size:clamp(25px,2.7vw,36px);letter-spacing:-.015em}
h3,.d4{font-size:clamp(19px,1.5vw,22px);letter-spacing:-.01em;line-height:1.18;
       font-variation-settings:'opsz' 36,'SOFT' 30}

.d1 em,.d2 em{font-style:italic;font-variation-settings:'opsz' 144,'SOFT' 60}

/* The one small-type voice on the site. Used for every label, everywhere. */
.lbl{
  font-family:var(--mono);
  font-size:11px;
  font-weight:700;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--pine);
  margin:0 0 clamp(14px,2vw,22px);
}
.lbl--amber{color:var(--amber)}

.lede{font-size:clamp(18px,1.55vw,21px);line-height:1.55;color:var(--ink-soft)}
.small{font-size:15px;color:var(--ink-soft)}
.fine{font-family:var(--mono);font-size:11.5px;letter-spacing:.11em;text-transform:uppercase;color:var(--ink-mute)}

/* A hairline that carries a label — used instead of a plain <hr>. */
.rule-lbl{display:flex;align-items:center;gap:18px;margin:0 0 clamp(22px,3vw,34px)}
.rule-lbl::after{content:'';flex:1;height:1px;background:var(--rule)}
.rule-lbl .lbl{margin:0}

/* 6. HEADER & NAVIGATION -------------------------------------------------- */

.hdr{
  position:sticky;top:0;z-index:60;
  background:rgba(250,248,243,.93);
  backdrop-filter:saturate(140%) blur(10px);
  border-bottom:1px solid transparent;
  transition:background-color .4s var(--ease-soft),border-color .4s var(--ease-soft),box-shadow .4s var(--ease-soft);
}
.hdr.is-scrolled{
  background:rgba(232,238,224,.94);
  border-bottom-color:rgba(44,122,69,.2);
  box-shadow:0 2px 24px rgba(38,36,31,.07);
}
.hdr-in{display:flex;align-items:center;gap:clamp(16px,3vw,34px);padding-block:12px;transition:padding .4s var(--ease-soft)}
.hdr.is-scrolled .hdr-in{padding-block:7px}

.brand{flex:none;line-height:0}
.brand img{height:70px;width:auto;transition:height .4s var(--ease-soft)}
.hdr.is-scrolled .brand img{height:56px}

.nav{display:flex;align-items:center;gap:clamp(14px,2vw,26px);margin-left:auto}
.nav a{
  font-family:var(--mono);font-size:12px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;text-decoration:none;
  padding:10px 0;position:relative;color:var(--ink);
}
/* Underline grows from the left rather than fading in. */
.nav a::after{
  content:'';position:absolute;left:0;bottom:4px;height:1.5px;width:100%;
  background:var(--pine);transform:scaleX(0);transform-origin:left;
  transition:transform .32s var(--ease);
}
.nav a:hover::after,.nav a[aria-current="page"]::after{transform:scaleX(1)}
.nav a[aria-current="page"]{color:var(--pine)}

.hdr-tel{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.06em;text-decoration:none;white-space:nowrap}
.navtoggle{display:none}

/* 7. BUTTONS & LINKS ------------------------------------------------------ */

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  min-height:48px;padding:13px 26px;
  font-family:var(--mono);font-size:12px;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;text-decoration:none;
  border:1.5px solid transparent;border-radius:2px;cursor:pointer;
  transition:background-color .22s,color .22s,border-color .22s,transform .22s var(--ease);
}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(0)}
/* Doubled class on purpose. A button sits inside contexts that set their own
   link colour — `.nav a`, `.section--ink a` — and those are a class plus a type,
   which outranks a single class. That is how the header CTA ended up dark green
   on green at 2.9:1 and the amber CTAs ended up white on amber at 2.1:1. */
.btn.btn--solid{background:var(--pine);color:var(--paper)}
.btn.btn--solid:hover{background:var(--pine-deep);color:var(--paper)}
.btn.btn--line{border-color:var(--rule-strong);color:var(--ink)}
.btn.btn--line:hover{border-color:var(--pine);color:var(--pine)}
.btn.btn--amber{background:var(--amber);color:var(--ink)}
.btn.btn--amber:hover{background:#f6a94f;color:var(--ink)}
.btn.btn--onink{border-color:var(--rule-dark);color:var(--paper)}
.btn.btn--onink:hover{background:var(--paper);color:var(--ink);border-color:var(--paper)}

/* Text link with a rule that draws under it. */
.tlink{
  font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;text-decoration:none;display:inline-flex;align-items:center;gap:9px;
  padding-bottom:3px;border-bottom:1.5px solid var(--rule-strong);
  transition:border-color .25s,gap .25s var(--ease),color .25s;
}
.tlink:hover{border-color:var(--pine);color:var(--pine);gap:14px}
.tlink svg{flex:none}

/* 8. THE PLAN MARK -------------------------------------------------------- */
/* The logo read as a plan view: centre paver, cross paths, shrubs on the rim.
   Used as the site's recurring mark. */

.mark{flex:none;display:block}
.mark--sm{width:40px;height:40px}
.mark--md{width:64px;height:64px}

/* Hero: the photograph runs off the right edge of the page rather than sitting
   in a tidy column beside the text.
   The left padding reproduces where .shell content begins, so the copy stays on
   the same line as the headline above it; the right padding is zero so the image
   reaches the true page edge at any viewport width. A negative margin on the
   figure itself won't do this — as a grid item its width is set by the track. */
.hero-grid{
  display:grid;
  grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  gap:clamp(24px,4vw,56px);
  align-items:end;
  padding-left:max(var(--gutter), calc((100vw - var(--sbw) - var(--maxw)) / 2 + var(--gutter)));
  padding-right:0;
}
.hero-grid .plan{aspect-ratio:3/2;border-radius:2px 0 0 2px}
.hero-grid .plan>img{height:100%;object-fit:cover;object-position:center 58%}


/* Hero. The photograph runs the full width of the window and the words sit on
   it, low and left, where the tarmac apron in the picture gives them a quiet
   ground of their own. The scrim only has to do the last bit of work. */
.hero-full{
  position:relative;display:flex;align-items:flex-end;overflow:hidden;
  width:calc(100vw - var(--sbw));margin-inline:calc(50% - 50vw + var(--sbw) / 2);
  min-height:min(92vh,920px);background:var(--ink);
}
.hero-shot{position:absolute;inset:0;margin:0}
.hero-shot img{width:100%;height:100%;object-fit:cover;object-position:center 56%;will-change:transform}
.hero-full::after{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:1;
  background:linear-gradient(to top,
    rgba(18,17,14,.9) 0%, rgba(18,17,14,.76) 18%, rgba(18,17,14,.5) 36%,
    rgba(18,17,14,.2) 54%, rgba(18,17,14,0) 72%);
}
.hero-copy{position:relative;z-index:2;width:100%;
  padding-top:clamp(140px,26vh,280px);padding-bottom:clamp(38px,5.5vw,74px)}
.hero-copy .lbl{color:var(--leaf)}
.hero-copy h1{color:var(--paper);font-size:clamp(46px,8vw,124px);max-width:13ch}
.hero-copy .lede{color:rgba(250,248,243,.88);max-width:46ch;margin:clamp(18px,2.4vw,30px) 0 0}
.hero-copy .btns{display:flex;flex-wrap:wrap;gap:12px;margin-top:clamp(24px,3vw,38px)}

/* 9. FRAMED PHOTOGRAPHY -------------------------------------------------- */
/* A photograph that carries a caption inside its own frame. Used once, on the
   Caswell House drone shot. */

.plan{position:relative;overflow:hidden;background:var(--stone);border-radius:2px}
.plan>img{width:100%;display:block;will-change:transform}
.plan-tag{
  position:absolute;right:12px;bottom:12px;
  font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--paper);background:rgba(38,36,31,.84);padding:6px 11px;border-radius:2px;
  opacity:0;transition:opacity .6s .35s;
}
.plan.is-in .plan-tag{opacity:1}

/* 10. COMPONENTS ---------------------------------------------------------- */

/* Photography. Crops vary by purpose — nothing is forced into one ratio. */
.shot{margin:0;position:relative}
.shot .frame{overflow:hidden;border-radius:2px;line-height:0;background:var(--stone)}
.shot img{width:100%;transition:transform .9s var(--ease-soft)}
.shot:hover img{transform:scale(1.04)}
.shot figcaption{display:flex;gap:12px;margin-top:14px;font-size:14.5px;color:var(--ink-soft);line-height:1.45}
.shot figcaption .n{font-family:var(--mono);font-size:11px;color:var(--amber-text);flex:none;padding-top:2px}
.r-tall img{aspect-ratio:4/5;object-fit:cover}
.r-port img{aspect-ratio:3/4;object-fit:cover}
.r-land img{aspect-ratio:3/2;object-fit:cover}
.r-wide img{aspect-ratio:16/9;object-fit:cover}
.r-sq img{aspect-ratio:1;object-fit:cover}
.r-round .frame{border-radius:50%}
.r-round img{aspect-ratio:1;object-fit:cover}

/* Services as an editorial index, not a grid of cards. */
.index{border-top:1px solid var(--rule)}
.index-row{
  display:grid;grid-template-columns:minmax(0,52px) minmax(0,1fr) minmax(0,1.35fr);
  gap:clamp(16px,3vw,40px);align-items:start;
  padding-block:clamp(22px,3vw,34px);border-bottom:1px solid var(--rule);
  transition:background-color .3s;
}
.index-row:hover{background:rgba(44,122,69,.035)}
.index-row .num{font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--amber-text);padding-top:7px}
.index-row h3{padding-top:1px}
.index-row p{margin:0;font-size:15.5px;color:var(--ink-soft);line-height:1.55}

/* Pull quote. One per page, big, no box around it. */
.pull{margin:0}
.pull blockquote{
  margin:0;font-family:var(--display);font-weight:500;
  font-size:clamp(23px,2.6vw,36px);line-height:1.24;letter-spacing:-.016em;
  font-variation-settings:'opsz' 90,'SOFT' 40;
}
.pull cite{
  display:block;margin-top:20px;font-family:var(--mono);font-style:normal;
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-mute);
}

/* Smaller review, used where several sit together. */
.review{border-top:1px solid var(--rule);padding-top:20px}
.review p{margin:0 0 14px;font-size:16px;line-height:1.55}
.review .who{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-mute)}
.stars{display:flex;gap:3px;margin-bottom:12px}
.stars svg{width:14px;height:14px;fill:var(--amber)}

/* Spec panel — the "facts" block. */
.spec{position:relative;overflow:hidden;background:var(--stone);border:1px solid var(--rule);border-radius:2px;padding:clamp(22px,3vw,32px)}
.spec dl{margin:0;position:relative;z-index:1}
.spec dl>div{display:flex;justify-content:space-between;gap:20px;padding-block:13px;border-bottom:1px solid var(--rule)}
.spec dl>div:last-child{border-bottom:0;padding-bottom:0}
.spec dt{font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-mute);padding-top:4px}
.spec dd{margin:0;font-family:var(--display);font-size:19px;font-weight:600;text-align:right;letter-spacing:-.01em}
.spec-mk{position:absolute;right:-56px;bottom:-56px;width:206px;height:206px;color:var(--pine);opacity:.22;z-index:0}

/* Form */
.field{display:flex;flex-direction:column;gap:7px}
.field label{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:rgba(250,248,243,.66)}
.field input,.field select,.field textarea{
  font-family:var(--body);font-size:16px;color:var(--paper);
  background:rgba(250,248,243,.06);border:1px solid var(--rule-dark);border-radius:2px;
  padding:13px 14px;width:100%;transition:border-color .25s,background-color .25s;
}
.field textarea{resize:vertical;min-height:112px}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--leaf);background:rgba(250,248,243,.1)}
.field .err{font-family:var(--mono);font-size:11px;color:#F2A5A5;min-height:14px}
.field.invalid input,.field.invalid select{border-color:#E08A8A}

/* 11. FOOTER -------------------------------------------------------------- */

.ftr{background:var(--stone);padding-top:var(--sp-s);padding-bottom:30px}
.ftr-grid{display:flex;flex-wrap:wrap;gap:34px 56px;justify-content:space-between;align-items:flex-start}
.ftr img.ftr-logo{height:88px;width:auto}
.ftr h4{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--pine-deep);margin:0 0 13px}
.ftr-col a,.ftr-col p{display:block;text-decoration:none;font-size:15px;color:var(--ink-soft);margin:0 0 8px}
.ftr-col a:hover{color:var(--pine-deep)}
.ftr-btm{display:flex;flex-wrap:wrap;gap:8px 24px;justify-content:space-between;
  margin-top:40px;padding-top:20px;border-top:1px solid var(--rule);font-size:13px;color:var(--ink-mute)}
.ftr-btm a{color:var(--pine-deep);text-decoration:none}
.ftr-btm a:hover{text-decoration:underline}

.social{display:flex;gap:10px}
.social{gap:16px}
/* No frame. These are the platforms' own marks and a tile round them reads as
   packaging; the padding is there purely to keep a 44px touch target. */
.soc{
  display:inline-flex;align-items:center;justify-content:center;
  padding:9px;margin:-9px;border:0;background:none;
  transition:opacity .22s,transform .22s var(--ease);
}
.soc img{width:26px;height:26px;display:block}
.soc:hover{opacity:.72;transform:translateY(-2px)}

/* Sticky mobile contact bar */
.mobilebar{display:none}

/* 12. MOTION -------------------------------------------------------------- */

.rv{opacity:0;transform:translateY(26px);
    transition:opacity .85s var(--ease),transform .85s var(--ease)}
.rv.is-in{opacity:1;transform:none}

/* Headlines arrive a line at a time, from under a mask, rather than fading in
   as one block. Lines are authored as spans — no runtime text-splitting, so
   nothing reflows badly if the font loads late or the text wraps differently. */
.lines{display:block}
.lines .ln{display:block;overflow:hidden;padding-bottom:.16em;margin-bottom:-.13em}
.lines .ln>span{display:block;transform:translateY(105%);
  transition:transform .95s var(--ease)}
.lines.is-in .ln>span{transform:none}
.lines .ln:nth-child(2)>span{transition-delay:.1s}
.lines .ln:nth-child(3)>span{transition-delay:.2s}

/* Photographs uncover rather than fade — the frame stays put and the image is
   revealed across it. Paired with the reveal on the caption underneath. */
.wipe .frame img,.wipe>img{clip-path:inset(0 100% 0 0);
  transition:clip-path 1.15s var(--ease),transform .9s var(--ease-soft)}
.wipe.is-in .frame img,.wipe.is-in>img{clip-path:inset(0 0 0 0)}
.wipe--up .frame img,.wipe--up>img{clip-path:inset(100% 0 0 0)}
.wipe--up.is-in .frame img,.wipe--up.is-in>img{clip-path:inset(0 0 0 0)}


/* 13. PAGE FURNITURE ------------------------------------------------------ */

/* Every inner page opens the same way: label, headline left, short deck set
   to the right on the same baseline, hairline underneath. It is the thing
   that makes six separate pages read as one site. */
.phead{padding-top:clamp(40px,6vw,86px);padding-bottom:clamp(26px,3.4vw,46px)}
.phead-grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);
  gap:clamp(18px,3vw,56px);align-items:end}
.phead h1{font-size:clamp(40px,6vw,82px)}
.phead .lede{margin:0;padding-bottom:9px}
.phead::after{content:'';display:block;height:1px;background:var(--rule);
  margin-top:clamp(26px,3.4vw,46px)}

/* Scroll progress. A hairline on the underside of the header — the only
   permanently-moving thing on the site, and it only moves because the
   reader does. */
.prog{position:absolute;left:0;bottom:-1px;height:1.5px;width:100%;
  background:var(--pine);transform:scaleX(0);transform-origin:left;
  opacity:0;transition:opacity .3s}
.hdr.is-scrolled .prog{opacity:.85}

/* Numbered process rail. Used once, on About. */
.steps{display:grid;gap:0;counter-reset:s}
.step{display:grid;grid-template-columns:minmax(0,74px) minmax(0,1fr);
  gap:clamp(14px,2.4vw,34px);padding-block:clamp(20px,2.6vw,30px);
  border-top:1px solid var(--rule);position:relative}
.step:last-child{border-bottom:1px solid var(--rule)}
.step-n{font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--amber-text);padding-top:6px}
.step h3{margin:0 0 7px}
.step p{margin:0;font-size:15.5px;color:var(--ink-soft);line-height:1.6;max-width:56ch}

/* A column that holds still while its neighbour scrolls. CSS only — the page
   never stops doing what the reader asked it to. */
.stick{position:sticky;top:clamp(96px,12vh,132px)}

/* Quiet caption used under feature photography. */
.cap{display:flex;gap:11px;margin-top:13px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.13em;text-transform:uppercase;color:var(--ink-mute)}
.cap b{font-weight:400;color:var(--amber-text)}

/* Project separator. */
.pmark{display:flex;align-items:baseline;gap:clamp(14px,2vw,28px);
  padding-top:clamp(44px,7vw,104px);padding-bottom:clamp(16px,2.2vw,28px)}
.pmark-n{font-family:var(--display);font-weight:600;line-height:.82;
  font-size:clamp(46px,7vw,104px);letter-spacing:-.035em;color:var(--stone-deep);
  font-variation-settings:'opsz' 144,'SOFT' 18;flex:none}
.pmark-t{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink-soft);flex:none}
.pmark-rule{flex:1;height:1px;min-width:20px;background:var(--rule-strong);
  transform:scaleX(0);transform-origin:left;transition:transform 1.15s var(--ease) .15s}
.pmark.is-in .pmark-rule{transform:none}
.section--stone .pmark-n{color:#CCC4B2}

/* 14. BEFORE & AFTER ------------------------------------------------------ */

/* Two photographs of the same ground, one on top of the other, revealed by a
   handle the reader drags. The range input underneath does the work so it is
   keyboard-operable and announced properly; everything visible is decoration. */
.ba{position:relative;overflow:hidden;border-radius:2px;background:var(--stone);
  --x:50%;touch-action:pan-y}
.ba img{width:100%;display:block;aspect-ratio:3/4;object-fit:cover}
.ba .ba-after{position:absolute;inset:0;height:100%;
  clip-path:inset(0 0 0 var(--x))}
.ba-line{position:absolute;top:0;bottom:0;left:var(--x);width:1.5px;
  background:var(--paper);box-shadow:0 0 0 1px rgba(38,36,31,.25);pointer-events:none}
.ba-grip{position:absolute;top:50%;left:var(--x);transform:translate(-50%,-50%);
  width:46px;height:46px;border-radius:50%;background:var(--paper);
  box-shadow:0 2px 14px rgba(38,36,31,.3);pointer-events:none;
  display:flex;align-items:center;justify-content:center;gap:3px}
.ba-grip svg{width:15px;height:15px;fill:var(--ink)}
.ba-lbl{position:absolute;bottom:12px;font-family:var(--mono);font-size:10px;
  font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--paper);
  background:rgba(38,36,31,.8);padding:5px 10px;border-radius:2px;pointer-events:none}
.ba-lbl.is-before{left:12px}
.ba-lbl.is-after{right:12px}
.ba input[type=range]{position:absolute;inset:0;width:100%;height:100%;margin:0;
  opacity:0;cursor:ew-resize;-webkit-appearance:none;appearance:none;background:none}
.ba input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:52px;height:100%}
.ba input[type=range]:focus-visible{opacity:1;outline:2px solid var(--pine);outline-offset:2px}

/* The other way of showing it: two frames side by side, the second wiping in
   as it arrives. Used where the two photographs aren't from the same spot and
   a slider would just look broken. */
.wb{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:4px}
.wb figure{margin:0;position:relative;overflow:hidden;border-radius:2px;background:var(--stone)}
.wb img{width:100%;aspect-ratio:3/4;object-fit:cover;display:block}
.wb .wb-tag{position:absolute;left:0;top:0;font-family:var(--mono);font-size:10px;
  font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--paper);
  background:rgba(38,36,31,.8);padding:6px 11px;border-radius:0 0 2px 0}
.wb figure:last-child img{clip-path:inset(0 0 0 100%);transition:clip-path 1.1s var(--ease) .15s}
.wb.is-in figure:last-child img{clip-path:inset(0 0 0 0)}

/* The four transformations. One grid rather than two columns, so the reading
   order on a phone is 01, 02, 03, 04 and not 01, 03, 02, 04. */
.ba-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  column-gap:clamp(16px,2.4vw,38px);row-gap:clamp(30px,4vw,56px);align-items:start}
.ba-grid>*:nth-child(2n){margin-top:clamp(0px,4vw,62px)}

/* 15. GALLERY & LIGHTBOX -------------------------------------------------- */

/* Rows are sized by script from each photograph's own height, so nothing is
   cropped to fit a tile. Joe's note was scan variety, little explanation. */
.gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));
  grid-auto-rows:8px;column-gap:clamp(10px,1.4vw,18px);
  /* Dense, because a double-width photograph that cannot fit the last column
     otherwise leaves a blank cell, and a hole in a gallery reads as a fault. */
  grid-auto-flow:row dense}
.gal-item{grid-row-end:span 40;margin:0;position:relative;overflow:hidden;
  border-radius:2px;background:var(--stone);cursor:zoom-in;
  opacity:0;transform:translateY(18px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.gal-item.is-in{opacity:1;transform:none}
.gal-item.is-wide{grid-column:span 2}
.gal-item img{width:100%;display:block;transition:transform 1s var(--ease-soft)}
.gal-item:hover img,.gal-item:focus-visible img{transform:scale(1.045)}
.gal-item figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 13px 11px;
  font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--paper);
  background:linear-gradient(to top,rgba(38,36,31,.72),transparent);
  opacity:0;transform:translateY(6px);transition:opacity .3s,transform .3s var(--ease)}
.gal-item:hover figcaption,.gal-item:focus-visible figcaption{opacity:1;transform:none}
.gal-item.is-hidden{display:none}

.filters{display:flex;flex-wrap:wrap;gap:6px 22px;align-items:center;
  padding-bottom:clamp(20px,2.6vw,30px);margin-bottom:clamp(20px,2.6vw,30px);
  border-bottom:1px solid var(--rule)}
.chip{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.13em;
  text-transform:uppercase;background:none;border:0;padding:8px 0;cursor:pointer;
  color:var(--ink-mute);position:relative;transition:color .25s}
.chip::after{content:'';position:absolute;left:0;right:0;bottom:3px;height:1.5px;
  background:var(--pine);transform:scaleX(0);transform-origin:left;
  transition:transform .3s var(--ease)}
.chip:hover{color:var(--ink)}
.chip[aria-pressed=true]{color:var(--pine)}
.chip[aria-pressed=true]::after{transform:scaleX(1)}

.lb{position:fixed;inset:0;z-index:200;background:rgba(24,23,19,.96);
  display:flex;align-items:center;justify-content:center;
  opacity:0;visibility:hidden;transition:opacity .34s var(--ease-soft),visibility .34s}
.lb.is-open{opacity:1;visibility:visible}
.lb img{max-width:min(94vw,1200px);max-height:82vh;width:auto;border-radius:2px;
  transform:scale(.97);transition:transform .34s var(--ease)}
.lb.is-open img{transform:none}
.lb-bar{position:absolute;left:0;right:0;bottom:0;display:flex;gap:18px;
  align-items:center;justify-content:space-between;padding:18px clamp(16px,3vw,30px);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:rgba(250,248,243,.66)}
.lb-btn{position:absolute;top:50%;transform:translateY(-50%);width:54px;height:54px;
  background:none;border:1px solid rgba(250,248,243,.24);border-radius:50%;cursor:pointer;
  color:var(--paper);display:flex;align-items:center;justify-content:center;
  transition:background-color .22s,border-color .22s}
.lb-btn:hover{background:rgba(250,248,243,.12);border-color:var(--paper)}
.lb-prev{left:clamp(10px,2vw,26px)}
.lb-next{right:clamp(10px,2vw,26px)}
.lb-close{position:absolute;top:clamp(12px,2vw,24px);right:clamp(12px,2vw,26px);
  width:46px;height:46px;transform:none}

/* 16. SERVICE DETAIL ------------------------------------------------------ */

/* One block per trade. The number sits out in its own rail, the text holds a
   narrow measure, and the photographs stack at their own sizes beside it. */
.svc{padding-block:clamp(42px,6vw,88px);border-top:1px solid var(--rule)}
.svc-grid{display:grid;grid-template-columns:minmax(0,64px) minmax(0,5fr) minmax(0,7fr);
  gap:clamp(18px,3vw,50px)}
.svc .svc-n{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.16em;
  color:var(--amber-text);padding-top:11px}
.svc h2{font-size:clamp(28px,3.4vw,46px);margin-bottom:16px}
.svc p{color:var(--ink-soft);margin:0 0 15px;font-size:16.5px;line-height:1.62}
.svc-list{list-style:none;margin:22px 0 0;padding:0;border-top:1px solid var(--rule)}
.svc-list li{display:flex;gap:12px;align-items:baseline;padding-block:10px;
  border-bottom:1px solid var(--rule);font-size:15px;color:var(--ink-soft)}
.svc-list li::before{content:'';flex:none;width:5px;height:5px;border-radius:50%;
  background:var(--leaf);transform:translateY(-2px)}
.svc-figs{display:grid;gap:clamp(10px,1.4vw,18px)}
.svc-figs.two{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:start}
.svc-figs .shot:nth-child(2){margin-top:clamp(0px,3vw,46px)}

/* 17. PEOPLE & REVIEWS ---------------------------------------------------- */

.people{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(16px,2.4vw,34px)}
.person{margin:0}
.person .frame{overflow:hidden;border-radius:2px;background:var(--stone);line-height:0}
.person img{width:100%;aspect-ratio:4/5;object-fit:cover;transition:transform .9s var(--ease-soft)}
.person:hover img{transform:scale(1.04)}
.person h3{margin:16px 0 0;padding-top:13px;border-top:1px solid var(--rule)}
.person .role{font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;
  text-transform:uppercase;color:var(--amber-text);margin:7px 0 0}
.person p{margin:10px 0 0;font-size:15px;color:var(--ink-soft);line-height:1.58}

/* The review wall. Columns rather than a grid, so the quotes keep their own
   lengths instead of being padded out to match each other. */
.rwall{columns:3;column-gap:clamp(18px,2.4vw,38px)}
.rquote{break-inside:avoid;margin:0 0 clamp(18px,2.4vw,34px);padding-top:18px;
  border-top:1px solid var(--rule)}
.rquote p{margin:12px 0 0;font-size:15.5px;line-height:1.6;color:var(--ink-soft)}
.rquote .who{display:flex;flex-wrap:wrap;gap:4px 12px;align-items:baseline;margin-top:14px}
.rquote .who b{font-family:var(--body);font-weight:600;font-size:15px;color:var(--ink)}
.rquote .src{font-family:var(--mono);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-mute)}
.rquote.is-long p{font-size:16.5px}

/* A tally, not a badge. */
.tally{display:flex;flex-wrap:wrap;gap:clamp(20px,4vw,64px);align-items:baseline}
.tally div{display:flex;gap:12px;align-items:baseline}
.tally .fig{font-family:var(--display);font-weight:600;font-size:clamp(34px,4vw,54px);
  letter-spacing:-.02em;font-variation-settings:'opsz' 120,'SOFT' 24}
.tally .lab{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-mute);max-width:15ch;line-height:1.5}


/* Stone is lighter than paper by enough to cost half a contrast point, so the
   two greens step down one tone on it. */
.section--stone .lbl,
.section--stone .chip[aria-pressed=true],
.section--stone .tlink:hover{color:var(--pine-deep)}
.section--stone .index-row:hover{background:rgba(44,122,69,.05)}

/* On ink the bright logo amber is the readable one — 6.9:1 — so it comes back. */
.section--ink .shot figcaption .n,
.section--ink .cap b,
.section--ink .svc .svc-n,.section--ink.svc .svc-n,
.section--ink .index-row .num{color:var(--amber)}

/* 18. ON A DARK GROUND ---------------------------------------------------- */
/* Collected here, after every component, for one reason: a component written
   further up the file sets its own colour and silently wins on source order.
   That is exactly how the services list ended up at 1.6:1 on the ink band. */

.section--ink .svc p,.section--ink.svc p,
.section--ink .svc-list li,.section--ink.svc .svc-list li,
.section--ink .step p,
.section--ink .small,
.section--ink .rquote p{color:rgba(250,248,243,.82)}
.section--ink .svc-list,.section--ink.svc .svc-list,
.section--ink .svc-list li,.section--ink.svc .svc-list li,
.section--ink .step,
.section--ink .review,
.section--ink .rquote,
.section--ink .index{border-color:var(--rule-dark)}
.section--ink .cap,
.section--ink .pull cite,
.section--ink .rquote .src,
.section--ink .fine,
.section--ink .tally .lab{color:rgba(250,248,243,.6)}
.section--ink .cap b{color:var(--leaf)}
.section--ink .tlink{border-bottom-color:var(--rule-dark)}
.section--ink .tlink:hover{border-bottom-color:var(--leaf);color:var(--leaf)}
.section--ink .shot figcaption,.section--ink.svc .shot figcaption{color:rgba(250,248,243,.7)}
.section--ink .spec{background:rgba(250,248,243,.05);border-color:var(--rule-dark)}
.section--ink .spec dl>div{border-color:var(--rule-dark)}
.section--ink .spec dt{color:rgba(250,248,243,.6)}
.section--ink .spec dd,
.section--ink .tally .fig{color:var(--paper)}

/* 19. RESPONSIVE ---------------------------------------------------------- */

@media (max-width:1000px){
  .g-7-5,.g-5-7,.g-8-4,.g-4-8{grid-template-columns:minmax(0,1fr)}
  .g-3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .index-row{grid-template-columns:minmax(0,40px) minmax(0,1fr);row-gap:8px}
  .index-row p{grid-column:2}
  .phead-grid{grid-template-columns:minmax(0,1fr);gap:16px}
  .phead .lede{padding-bottom:0}
  .svc-grid{grid-template-columns:minmax(0,46px) minmax(0,1fr);row-gap:26px}
  .svc-figs{grid-column:1/-1}
  .rwall{columns:2}
  .stick{position:static}
}

@media (max-width:760px){
  body{font-size:16px}
  .nav{
    position:fixed;inset:0 0 auto;top:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--paper);padding:88px var(--gutter) 30px;
    transform:translateY(-102%);transition:transform .45s var(--ease);
    box-shadow:0 20px 50px rgba(38,36,31,.16);margin-left:0;
  }
  .nav.is-open{transform:none}
  .nav a{font-size:15px;padding:16px 0;border-bottom:1px solid var(--rule)}
  .nav a::after{display:none}
  .hdr-tel{display:none}
  .navtoggle{
    display:inline-flex;align-items:center;justify-content:center;
    width:46px;height:46px;margin-left:auto;background:none;
    border:1px solid var(--rule-strong);border-radius:2px;cursor:pointer;z-index:70;
  }
  .navtoggle span{display:block;width:19px;height:1.5px;background:var(--ink);position:relative;transition:background-color .2s}
  .navtoggle span::before,.navtoggle span::after{
    content:'';position:absolute;left:0;width:19px;height:1.5px;background:var(--ink);
    transition:transform .3s var(--ease)}
  .navtoggle span::before{top:-6px}
  .navtoggle span::after{top:6px}
  .navtoggle[aria-expanded="true"] span{background:transparent}
  .navtoggle[aria-expanded="true"] span::before{transform:translateY(6px) rotate(45deg)}
  .navtoggle[aria-expanded="true"] span::after{transform:translateY(-6px) rotate(-45deg)}

  .brand img{height:56px}
  .hdr.is-scrolled .brand img{height:50px}

  .hero-grid{grid-template-columns:minmax(0,1fr);padding-left:var(--gutter);padding-right:var(--gutter);gap:26px}
  .hero-grid .plan{max-height:none;border-radius:2px}
  /* The hero photograph is landscape and a phone is not. Cropping it to a
     portrait window would throw both gate posts off the sides, so on mobile the
     picture is shown whole and the words sit under it, on the same dark ground.
     One section still, no scrim needed, nothing squeezed. */
  .hero-full{display:block;min-height:0}
  .hero-shot{position:static;inset:auto}
  .hero-shot img{height:auto;aspect-ratio:4/3;object-position:center 58%}
  .hero-full::after{display:none}
  .hero-copy{padding-top:clamp(26px,5vw,38px);padding-bottom:clamp(30px,6vw,44px)}
  .g-3,.g-2{grid-template-columns:minmax(0,1fr)}
  .spec-mk{right:-70px;bottom:-70px;opacity:.16}

  /* Mobile gets its own crops — portraits are too tall on a phone. */
  .r-tall img,.r-port img{aspect-ratio:4/3}
  .rwall{columns:1}
  /* The project name can be long enough to push the page sideways on a phone,
     so on mobile it wraps under the numeral and takes the rule with it. */
  .pmark{gap:8px 14px;flex-wrap:wrap;align-items:center;padding-top:clamp(34px,9vw,54px)}
  .pmark-t{font-size:10px;letter-spacing:.13em;white-space:normal;flex:1 1 60%;min-width:0}
  .pmark-rule{flex:1 1 100%}
  .people{grid-template-columns:minmax(0,1fr);gap:30px}
  .person img{aspect-ratio:4/3}
  .svc-figs.two{grid-template-columns:minmax(0,1fr)}
  .svc-figs .shot:nth-child(2){margin-top:0}
  .gal{grid-template-columns:repeat(2,minmax(0,1fr))}
  .gal-item.is-wide{grid-column:span 2}
  /* A two-up on a phone makes both halves unreadable — stack them. */
  .wb{grid-template-columns:minmax(0,1fr);gap:6px}
  .wb figure:last-child img{clip-path:none}
  .ba-grid{grid-template-columns:minmax(0,1fr);row-gap:34px}
  .ba-grid>*:nth-child(2n){margin-top:0}
  .ba img,.wb img{aspect-ratio:4/5}
  .ba-grip{width:40px;height:40px}
  .lb-btn{width:44px;height:44px}
  .lb-prev{left:6px}
  .lb-next{right:6px}
  .tally{gap:22px 34px}
  .r-round .frame{border-radius:2px}
  .r-round img{aspect-ratio:4/3}

  .mobilebar{
    display:grid;grid-template-columns:1fr 1fr;gap:1px;
    position:fixed;left:0;right:0;bottom:0;z-index:80;
    background:rgba(38,36,31,.16);box-shadow:0 -2px 18px rgba(38,36,31,.16);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .mobilebar a{
    display:flex;align-items:center;justify-content:center;gap:8px;min-height:54px;
    font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.08em;
    text-transform:uppercase;text-decoration:none;
  }
  .mb-wa{background:#1F8F4E;color:#fff}
  .mb-call{background:var(--ink);color:var(--paper)}
  body{padding-bottom:56px}
}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms!important;transition-duration:.001ms!important;transition-delay:0ms!important}
  .rv{opacity:1;transform:none}
  .plan-tag{opacity:1}
  .lines .ln>span{transform:none}
  .wipe .frame img,.wipe>img,.wb figure:last-child img{clip-path:none}
  .gal-item{opacity:1;transform:none}
  .btn:hover,.soc:hover{transform:none}
  .shot:hover img{transform:none}
}

@media print{
  .hdr,.mobilebar,.navtoggle{display:none}
  body{background:#fff;color:#000}
}
