/* Gas Connect Limited — extracted from Gas_Connect.html (single-file build).
   source <style> block(s) 2 of 19
   Load order is significant: see index.html. */

/* ---- source <style> ---- */
/* ================= TOKENS ================= */
:root{
  --paper:#FAF8F2; --card:#F3F0E7; --mist:#E9EFE6; --linen:#F6F3EA;
  --ink:#20302A; --ink-2:#57685F; --ink-3:#8B978E;
  --green:#5a8755; --green-deep:#3f5f3c; --green-soft:#7ea378;
  --brown:#774e2c; --brown-deep:#55371f;
  --tint:#dbe6d3; --tint-dim:#9fb797;
  --grey:#b8bfb6; --grey-deep:#8b9389;
  /* distinct per-service accents for the orbit diagram — each service line
     gets its own hue (rather than cycling shades of the same green/brown)
     so the ring reads with real colour variety. -rgb twins exist purely so
     the glow/box-shadow rules below can use rgba() with these colours. */
  --acc-lpg:#5a8755; --acc-lpg-rgb:90,135,85;
  --acc-reticulation:#2f7a86; --acc-reticulation-rgb:47,122,134;
  --acc-autogas:#c1703a; --acc-autogas-rgb:193,112,58;
  --acc-metering:#a98a2e; --acc-metering-rgb:169,138,46;
  --acc-lifecycle:#a4462f; --acc-lifecycle-rgb:164,70,47;
  --line:rgba(32,48,42,.14); --line-strong:rgba(32,48,42,.28);
  /* Type scale — golden ratio (φ=1.618), 10 steps. Each is φ^n where n ∈ [-2,−1,0,0.5,1,1.5,2,2.5,3,4]:
     caption φ⁻²·0.382 · label φ⁻¹·0.618 · body φ⁰·1.0 · lead φ⁰·⁵·1.272
     h4 φ¹·1.618 · h3 φ¹·⁵·2.058 · h2 φ²·2.618 · h1 φ²·⁵·3.330 · hero φ³·5.388 · display φ⁴·8.714

     DELIBERATE BREAK: the two sub-body steps no longer follow φ. Held to the
     ratio, caption computed to 6.1px on phones and never exceeded 7.7px on
     desktop, and label bottomed out at 9.9px — both illegible, and caption has
     44 consumers including form labels and the stat descriptions. φ governs
     body and everything above it; these two are floored for legibility.
     caption 10.5→12px · label 12→13.5px */
  --t-caption:clamp(0.656rem,0.6rem + 0.15vw,0.75rem);
  --t-label:clamp(0.75rem,0.7rem + 0.14vw,0.844rem);
  --t-body:1rem;
  --t-lead:clamp(1.1rem,1rem + 0.4vw,1.272rem);
  --t-h4:clamp(1.272rem,1.1rem + 0.6vw,1.618rem);
  --t-h3:clamp(1.618rem,1.4rem + 1vw,2.058rem);
  --t-h2:clamp(2.058rem,1.6rem + 2vw,2.618rem);
  --t-h1:clamp(2.618rem,2rem + 2.8vw,3.2rem);
  --t-hero:clamp(3.330rem,2.2rem + 4vw,5.388rem);
  --t-display:clamp(5.388rem,3rem + 6vw,8.714rem);
  --sp-1:.65rem; --sp-2:1.15rem; --sp-3:2rem; --sp-4:3.4rem; --sp-5:5.5rem;
  --gutter:clamp(1.2rem,4vw,4rem); --maxw:1200px;
  --ease:cubic-bezier(.22,.9,.28,1);
  --ease-spring:cubic-bezier(.34,1.28,.5,1);
  --shadow:0 16px 48px rgba(14,60,45,.14);
  --shadow-deep:0 24px 64px rgba(14,60,45,.2);
}
/* ================= RESET / BASE ================= */
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:'Inter',system-ui,sans-serif;font-size:var(--t-body);line-height:1.65;
  color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased}
/* Ambient colour frame — sits fixed to the viewport (so it stays put while
   the page scrolls) above every section's own background, but well below
   the nav (z-index 210) and intro overlay (500). Four soft corner glows,
   each faded out well before reaching the middle of the screen, so body
   copy always sits on clean paper — only the margins pick up colour. Reuses
   the same accent set as the orbit diagram (green / teal / amber /
   terracotta) so the two live in the same palette rather than introducing
   a new one just for this. pointer-events:none — decoration only, never
   intercepts a click. */
.page-frame{position:fixed;inset:0;z-index:5;pointer-events:none;
  background:
    radial-gradient(38vw 38vw at -8% -10%, rgba(var(--acc-lpg-rgb),.30) 0%, transparent 70%),
    radial-gradient(34vw 34vw at 108% -8%, rgba(var(--acc-reticulation-rgb),.26) 0%, transparent 70%),
    radial-gradient(36vw 36vw at 106% 106%, rgba(var(--acc-lifecycle-rgb),.24) 0%, transparent 70%),
    radial-gradient(34vw 34vw at -6% 108%, rgba(var(--acc-autogas-rgb),.24) 0%, transparent 70%);
}
@media (max-width:720px){
  .page-frame{background:
    radial-gradient(60vw 60vw at -12% -10%, rgba(var(--acc-lpg-rgb),.26) 0%, transparent 68%),
    radial-gradient(55vw 55vw at 112% -8%, rgba(var(--acc-reticulation-rgb),.22) 0%, transparent 68%),
    radial-gradient(58vw 58vw at 108% 108%, rgba(var(--acc-lifecycle-rgb),.2) 0%, transparent 68%),
    radial-gradient(55vw 55vw at -10% 110%, rgba(var(--acc-autogas-rgb),.2) 0%, transparent 68%);
  }
}
img,svg{display:block;max-width:100%}
a{color:inherit}
input,select,textarea{font:inherit;color:inherit}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
::selection{background:var(--tint);color:var(--green-deep)}
:focus-visible{outline:2px solid var(--green);outline-offset:3px;border-radius:2px}
[tabindex="-1"]:focus-visible{outline:none}

.display{font-family:'Fraunces',serif;font-optical-sizing:auto}
.mono{font-family:'IBM Plex Mono',monospace;font-size:var(--t-label);font-weight:500;
  letter-spacing:.14em;text-transform:uppercase}
.amp{font-style:italic;font-weight:400;padding:0 .02em}

/* ================= PHOTO PIPELINE ================= */
.photo{position:absolute;inset:0;z-index:1;background-position:var(--photo-pos,center);
  background-size:cover;opacity:0;transition:opacity .8s ease;
  filter:brightness(var(--pb,.98)) contrast(var(--pc,1.06)) saturate(var(--sat,.8))}
.photo.is-loaded{opacity:1}
.photo::after{content:"";position:absolute;inset:0;background:var(--green);
  mix-blend-mode:color;opacity:var(--duo,.42);pointer-events:none}
/* Duotone strength tuned by the job each section does: loud on the atmosphere
   bookends (hero/contact), medium on the framed working figures (about/markets),
   near-documentary on Projects so a real installation reads as proof, not styling. */
#contact .photo{--duo:0;--sat:1;--pb:1;--pc:1;background-size:100% auto;background-repeat:no-repeat}
/* Hero: no tint, no desaturation, no dampened brightness/contrast — the photo
   reads in its own true colour. The seam below it is handled by sampling
   that true colour, not by grading the image to fit a fixed palette. */
#intake .photo{--duo:0;--sat:1;--pb:1;--pc:1}
#projects .photo{--duo:.10;--sat:.98;--pb:1;--pc:1.04}

/* ================= INTRO / SPLASH SCREEN ================= */
/* Wrapper has no scroll height — pure fixed overlay */
.intro-wrap{position:fixed;inset:0;z-index:500;pointer-events:none}
.intro{
  position:absolute;inset:0;
  display:flex;align-items:center;justify-content:center;
  background:var(--paper);
  overflow:hidden;
  /* fades out once animation completes */
  transition:opacity .4s ease .1s, visibility .4s ease .1s;
}
.intro.is-done{
  opacity:0;
  visibility:hidden;
  pointer-events:none;
}
.intro__logo{
  position:absolute;
  will-change:transform,width,top,left;
  /* start state: centred */
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
  width:clamp(200px,30vw,380px);
  height:auto;
  /* flight transition — ease-in-out, triggered by .is-flying class */
  transition:
    left   0.9s cubic-bezier(0.76,0,0.24,1),
    top    0.9s cubic-bezier(0.76,0,0.24,1),
    width  0.9s cubic-bezier(0.76,0,0.24,1),
    transform 0.9s cubic-bezier(0.76,0,0.24,1),
    opacity 0.35s ease;
}
.intro__logo svg{width:100%;height:auto;display:block}
/* Bottom-of-splash ticker: sits under the centred logo while it holds, then
   slides right off the edge in lockstep with the logo's own fly-up — same
   duration/easing as the logo's left/top/width transition — so both moves
   read as one departure rather than two separate animations. Uses 'left'
   (not transform) for the fly so it can share that transition list cleanly. */
.intro-ticker{position:absolute;left:50%;bottom:clamp(2.2rem,9vh,4.5rem);
  transform:translateX(-50%);
  display:flex;align-items:center;opacity:0;
  transition:left .9s cubic-bezier(0.76,0,0.24,1),opacity .5s ease .35s;
  will-change:left,opacity}
.intro-ticker.is-visible{opacity:1}
.intro-ticker__mask{position:relative;overflow:hidden;width:12rem;
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 1rem,#000 calc(100% - 1rem),transparent 100%);
  mask-image:linear-gradient(to right,transparent 0,#000 1rem,#000 calc(100% - 1rem),transparent 100%)}
.intro-ticker__track{display:flex;width:max-content;animation:lt-scroll 11s linear infinite}
@media (max-width:640px){
  .intro-ticker__mask{width:9.5rem}
}
@media(prefers-reduced-motion:reduce){
  .intro-ticker__track{animation:none}
}
/* Nav logo hidden until intro logo lands */
.nav{transition:opacity .5s,visibility .5s,background .5s,border-color .5s,backdrop-filter .5s}
.nav.intro-phase{
  background:transparent;
  backdrop-filter:none;-webkit-backdrop-filter:none;
  border-bottom-color:transparent;
  pointer-events:none;
}
/* During intro, only the Contact button and links are hidden — not the nav shell */
.nav.intro-phase .nav__links,
.nav.intro-phase .nav__burger,
.nav.intro-phase .lens-fab,
.nav.intro-phase .btn{opacity:0;pointer-events:none}
/* Wayfinder also hidden during intro */
.nav.intro-phase ~ * .wayfinder,
body:has(.nav.intro-phase) .wayfinder{opacity:0;pointer-events:none}
.nav__brand{transition:opacity .4s}
.nav__brand.intro-hidden{opacity:0;pointer-events:none}


/* ================= TOP BAR ================= */
.nav{position:fixed;inset:0 0 auto 0;z-index:210;display:flex;align-items:center;gap:var(--sp-3);
  padding:.9rem var(--gutter);
  background:rgba(250,248,242,.82);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-bottom:1px solid var(--line)}
.nav__brand{display:flex;align-items:center;text-decoration:none;margin-right:auto;
  position:relative;cursor:pointer;-webkit-tap-highlight-color:transparent;
  -webkit-user-select:none;user-select:none}
/* hamburger */
.nav__burger{display:none;flex-direction:column;justify-content:center;align-items:center;gap:5px;
  width:44px;height:44px;background:none;border:none;cursor:pointer;padding:8px;
  border-radius:8px;transition:background .2s}
.nav__burger:hover{background:var(--mist)}
.nav__burger span{display:block;width:22px;height:2px;background:var(--ink);border-radius:2px;
  transition:transform .3s var(--ease-spring),opacity .2s,width .3s}
.nav__burger.is-open span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav__burger.is-open span:nth-child(2){opacity:0;width:0}
.nav__burger.is-open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
/* mobile drawer */
.nav__drawer{display:none;position:fixed;inset:0;z-index:205;background:rgba(250,248,242,.97);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  flex-direction:column;align-items:center;justify-content:center;gap:0;
  opacity:0;pointer-events:none;transition:opacity .3s var(--ease)}
.nav__drawer.is-open{opacity:1;pointer-events:auto}
.nav__drawer a{display:block;font-family:'Fraunces',serif;font-size:var(--t-h2);
  font-weight:380;color:var(--ink);text-decoration:none;padding:.6rem 2rem;
  text-align:center;transition:color .2s,transform .3s var(--ease-spring);
  letter-spacing:-.01em;line-height:1.2}
.nav__drawer a:hover{color:var(--green);transform:translateX(4px)}
.nav__drawer a[aria-current="true"]{color:var(--green)}
.nav__drawer .drawer__lens{margin-top:2rem;display:flex;gap:.6rem;justify-content:center}
.nav__drawer .drawer__close{position:absolute;top:1.2rem;right:1.2rem;
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  background:none;border:none;cursor:pointer;font-size:var(--t-lead);color:var(--ink-2);
  border-radius:8px;transition:background .2s}
.nav__drawer .drawer__close:hover{background:var(--mist)}
@keyframes pulse-brand{0%{transform:scale(1)}40%{transform:scale(1.08)}100%{transform:scale(1)}}
.nav__brand.pulse{animation:pulse-brand .5s var(--ease-spring)}
.sdg-stamp{position:fixed;bottom:1.4rem;left:50%;transform:translateX(-50%) translateY(12px);
  z-index:500;background:var(--green-deep);color:var(--paper);font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-caption);letter-spacing:.12em;text-transform:uppercase;padding:.3rem .8rem;border-radius:2rem;
  opacity:0;pointer-events:none;transition:opacity .4s ease,transform .4s var(--ease-spring);white-space:nowrap}
.sdg-stamp.show{opacity:1;transform:translateX(-50%) translateY(0)}
.nav__links{display:flex;gap:var(--sp-3);list-style:none;overflow-x:auto;scrollbar-width:none}
.nav__links::-webkit-scrollbar{display:none}
.nav__links a{position:relative;font-size:var(--t-label);font-weight:500;color:var(--ink-2);text-decoration:none;
  transition:color .25s;white-space:nowrap}
.nav__links a:hover{color:var(--ink)}
.nav__links a[aria-current="true"]{color:var(--green);font-weight:600}
.nav__links a[aria-current="true"]::after{content:"";position:absolute;left:50%;bottom:-.6rem;
  width:4px;height:4px;border-radius:50%;background:var(--green);transform:translateX(-50%)}

.wayfinder{position:fixed;left:var(--gutter);bottom:1.4rem;z-index:200;display:flex;align-items:center;gap:.6rem;
  padding:.55rem 1rem;border-radius:999px;background:rgba(250,248,242,.86);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid var(--line);
  box-shadow:0 8px 24px rgba(32,48,42,.08)}
.wayfinder__no{font-family:'IBM Plex Mono',monospace;font-size:var(--t-label);font-weight:600;letter-spacing:.06em;
  color:var(--green);min-width:1.3em;display:inline-block;transition:opacity .25s,transform .3s var(--ease)}
.wayfinder__bar{width:14px;height:1px;background:var(--line-strong)}
.wayfinder__label{font-family:'IBM Plex Mono',monospace;font-size:var(--t-caption);font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-2);transition:opacity .25s,transform .3s var(--ease)}
.wayfinder.is-changing .wayfinder__no,.wayfinder.is-changing .wayfinder__label{opacity:0;transform:translateY(4px)}
@media (max-width:980px){ .wayfinder{display:none} }

.btn{display:inline-flex;align-items:center;gap:.6em;font-size:var(--t-label);font-weight:600;letter-spacing:.02em;
  padding:.8em 1.5em;min-height:44px;border-radius:999px;text-decoration:none;border:1.5px solid transparent;
  transition:background .3s,border-color .3s,color .3s,transform .4s var(--ease-spring)}
.btn--solid{background:var(--green);color:var(--paper)}
.btn--solid:hover{background:var(--green-deep)}
.btn--brown{background:var(--brown);color:#fff}
.btn--brown:hover{background:var(--brown-deep);color:#fff}
.btn--ghost{border-color:var(--line-strong);color:var(--ink)}
.btn--ghost:hover{border-color:var(--green)}
.btn__arrow{transition:transform .35s var(--ease)}
.btn:hover .btn__arrow{transform:translateX(3px)}
.btn:active{transform:scale(.97);transition-duration:.1s}

/* ================= PAGE / SECTION ================= */
.page{
  position:relative;
  /* v90 shrink-and-fade: GPU layer always ready, collapses toward its own
     top edge as it leaves. */
  will-change:transform,opacity;
  transform-origin:50% 0;
  transform:scale(1);
  opacity:1;
  padding:calc(3.6rem + var(--sp-2)) var(--gutter) var(--sp-4);
  overflow:hidden;
  /* Each section is its own page: fills the viewport, content centred, so the
     next section never peeks at the bottom edge.
     min-height, NOT height — a section taller than the viewport (About,
     Investors) simply grows past it. And because it grows, the flex container
     never has free space to distribute, so justify-content:center can never
     push content out of the top and get clipped by overflow:hidden. */
  min-height:100dvh;
  display:flex;
  flex-direction:column;
  justify-content:center;
  /* Scale stack — GPU layer always ready */
  will-change:transform,opacity;
  transform-origin:50% 0;          /* collapses toward top-center like BIG */
  transform:scale(1);
  opacity:1;
  transition:none;                  /* JS drives this, no CSS transition */
}
/* Wrapper that clips the scaled section so it doesn't overlap neighbours */
.page-scale-wrap{
  overflow:hidden;
  border-radius:0;
}
/* padding-bottom was 1.5rem (24px) flat. justify-content:center only adds
   breathing room ABOVE that floor when content is shorter than the viewport —
   it never adds room below the floor. Customer copy (shortest sub, shortest
   proof-strip items) sits well under 100dvh, so it gets extra centred slack
   and looks fine. Partner/investor copy (longer thesis, longer CTA label,
   longer proof items) runs close to or past 100dvh, so the flex box has no
   slack left to distribute and the content sits flush on the bare 24px floor
   at both top and bottom — reading as pressed into the edges. Raising the
   floor itself (not the centring) fixes every lens, including the ones that
   currently look fine, since it only ever adds room, never removes it. */
.page--hero{min-height:100dvh;display:flex;flex-direction:column;justify-content:center;
  padding-top:calc(4.4rem + 1vh);padding-bottom:clamp(2.4rem,6vh,4rem);scroll-margin-top:0}
.page{background:var(--paper)}
.page__bg{position:absolute;inset:0;z-index:0}
.page__bg::before{content:"";position:absolute;inset:0}
#intake .page__bg::before{background:linear-gradient(130deg,var(--linen) 0%,var(--paper) 48%,var(--seam-color,var(--mist)) 100%);transition:background .6s ease}
#origin .page__bg::before{
  background:
    radial-gradient(55% 65% at 80% 32%, var(--origin-glow-a,transparent) 0%, transparent 62%),
    radial-gradient(50% 60% at 80% 78%, var(--origin-glow-b,transparent) 0%, transparent 65%),
    linear-gradient(210deg,var(--seam-color,var(--mist)) 0%,var(--paper) 55%,var(--linen) 100%);
  transition:background .6s ease
}
#services .page__bg::before{background:linear-gradient(155deg,var(--card) 0%,var(--linen) 45%,var(--paper) 100%)}
#markets .page__bg::before{background:linear-gradient(195deg,var(--mist) 0%,var(--paper) 60%,var(--linen) 100%)}
#projects .page__bg::before{background:linear-gradient(165deg,var(--linen) 0%,var(--paper) 50%,var(--card) 100%)}
#investors .page__bg::before{background:radial-gradient(130% 130% at 15% 10%,var(--card) 0%,var(--linen) 45%,var(--paper) 80%)}
#contact .page__bg::before{background:linear-gradient(145deg,var(--mist) 0%,var(--paper) 55%,var(--linen) 100%)}
.scrim{position:absolute;inset:0;z-index:2}
.scrim--left{background:linear-gradient(90deg,rgba(250,248,242,.95) 0%,rgba(250,248,242,.72) 42%,rgba(250,248,242,.12) 74%,transparent 100%)}
.scrim--full{background:linear-gradient(110deg,rgba(250,248,242,.94) 0%,rgba(250,248,242,.82) 55%,rgba(250,248,242,.6) 100%)}
.scrim--bottom{background:linear-gradient(to top,rgba(20,40,30,.55),transparent 55%)}

/* ===== Hero → About seam ==========================================
   #intake's own gradient already ends on var(--mist) to match #origin's
   gradient start (see the two rules above) — that hand-off was already
   colour-matched. What broke the seam was the PHOTO sitting on top of it:
   a real aerial image has a hard bottom edge, so the section boundary read
   as a photo being sliced off rather than a scene dissolving into paper.
   Fading the photo + scrim out over the last third of the hero lets the
   matched gradient show through first, so by the time About begins the
   colour is already continuous — no seam to see. ==================== */
#intake .page__bg .photo,
#intake .page__bg .scrim{
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 55%,transparent 94%);
          mask-image:linear-gradient(to bottom,#000 0%,#000 55%,transparent 94%);
}
.wrap{position:relative;z-index:3;width:100%;max-width:var(--maxw);margin-inline:auto}

/* reveals */
.reveal{opacity:0;transform:translateY(16px);transition:opacity .7s ease,transform .7s var(--ease)}
.reveal.in{opacity:1;transform:none}
.stagger>*{opacity:0;transform:translateY(14px);transition:opacity .6s ease,transform .6s var(--ease)}
.stagger.in>*{opacity:1;transform:none}
.stagger.in>*:nth-child(1){transition-delay:.04s}
.stagger.in>*:nth-child(2){transition-delay:.12s}
.stagger.in>*:nth-child(3){transition-delay:.21s}
.stagger.in>*:nth-child(4){transition-delay:.3s}
.stagger.in>*:nth-child(5){transition-delay:.39s}
.stagger.in>*:nth-child(6){transition-delay:.48s}
/* section-tuned reveal speeds */
#intake .reveal,#intake .stagger>*{transition-duration:.32s;transition-timing-function:cubic-bezier(.2,.8,.3,1)}
#services .reveal,#services .stagger>*{transition-duration:.5s}
#markets .reveal,#markets .stagger>*{transition-duration:.5s}
#origin .reveal,#origin .stagger>*{transition-duration:.85s;transition-timing-function:cubic-bezier(.4,0,.2,1)}
#projects .reveal,#projects .stagger>*{transition-duration:.9s;transition-timing-function:cubic-bezier(.4,0,.2,1)}
#investors .reveal,#investors .stagger>*{transition-duration:1s;transition-timing-function:cubic-bezier(.4,0,.2,1)}

/* ================= SHARED EDITORIAL ================= */
.eyebrow{display:inline-flex;align-items:center;gap:.6em;color:var(--green);margin-bottom:var(--sp-2);font-size:clamp(0.875rem,0.7rem + 0.6vw,1.1rem)}
.eyebrow::before{content:"";width:22px;height:2px;background:var(--green)}
.lead{font-size:var(--t-lead);color:var(--ink-2);line-height:1.58;max-width:56ch}
.lead .hl{background:var(--tint);color:var(--green-deep);padding:0 .16em;border-radius:3px;
  box-decoration-break:clone;-webkit-box-decoration-break:clone}
.h1{font-size:var(--t-display);font-weight:360;line-height:.99;letter-spacing:-.02em;text-wrap:balance}
.h2{font-size:var(--t-h2);font-weight:380;line-height:1.06;letter-spacing:-.015em;text-wrap:balance}
.h2 em,.h1 em{font-style:italic;color:var(--green)}
.pullquote{font-family:'Fraunces',serif;font-optical-sizing:auto;font-style:italic;font-weight:400;
  font-size:clamp(1.272rem,1rem + 1.9vw,2.058rem);line-height:1.15;max-width:40ch;
  border-left:2px solid var(--brown);padding-left:var(--sp-2);margin-top:var(--sp-3);text-wrap:balance}
.pullquote--wide{max-width:none;margin-top:var(--sp-4);
  font-size:clamp(1.618rem,1.1rem + 2.6vw,2.618rem)}
.pill{font-family:'IBM Plex Mono',monospace;font-size:var(--t-caption);font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--green);background:rgba(90,135,85,.09);
  padding:.4em .9em;border-radius:999px;white-space:nowrap}
/* Frames — the default is NO frame.
   Most images on this page are feathered cut-outs whose own alpha carries
   the edge, so the old default (radius + border + shadow + gradient fill)
   had to be stripped back out by about a dozen override rules. Inverted:
   bare .frame draws nothing, and the two images that genuinely want a mount
   opt in with .frame--plate. Square corners and no shadow — the page is set
   on hairlines and flat paper everywhere else, and a soft drop shadow made
   photographs float off a document that otherwise sits flat. */
.frame{position:relative;overflow:visible;border:0;border-radius:0;box-shadow:none;background:none}
.frame--plate{overflow:hidden;border:1px solid var(--line);background:linear-gradient(155deg,var(--linen),var(--mist))}
.frame__cap{margin-top:.7rem;color:var(--ink-3);display:inline-flex;align-items:center;gap:.55em}
.frame__cap::before{content:"";width:18px;height:1px;background:var(--tint-dim);flex:none}

/* ================= 00 HOME ================= */
.intake{display:block}
.intake>div{max-width:var(--maxw);display:flex;flex-direction:column}
.page--hero #heroEyebrow{font-size:clamp(0.85rem,0.78rem + 0.2vw,1rem);line-height:1.3;margin-bottom:.9rem}
.page--hero .h1{max-width:19ch;font-size:clamp(2.3rem,1.7rem + 2.6vw,3.2rem);line-height:1.03;margin-top:0}
.page--hero .intake__sub{max-width:56ch;font-size:clamp(1rem,0.94rem + 0.2vw,1.1rem);line-height:1.55;margin-top:1.1rem}
/* Hero CTA: .intake>div is a flex column with align-items:stretch, so this
   inline-flex pill spans the doors' full width in every lens. Left-aligned
   content then read as the label being shoved against the edge on the longer
   partner/investor labels. Centre it — same bar width across all three lenses,
   matching the .btn--full pattern used further down the page. */
#heroCta{justify-content:center;text-align:center}
.hero-badge{display:none}
.tagline{font-family:'IBM Plex Mono',monospace;font-size:var(--t-label);letter-spacing:.22em;text-transform:uppercase;
  color:var(--brown);margin-top:var(--sp-2);display:flex;gap:.7em;align-items:center;flex-wrap:wrap}
.tagline span{opacity:.5}
.doors__lab{font-family:'IBM Plex Mono',monospace;font-size:clamp(0.85rem,0.78rem + 0.2vw,1rem);font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3);margin-top:2.1rem;margin-bottom:.9rem;display:flex;align-items:center;gap:.6em}
.doors__lab::before{content:"";width:22px;height:1px;background:var(--tint-dim)}
.doors{margin-top:0;display:grid;grid-template-columns:repeat(3,1fr);gap:1.2rem;align-items:stretch}
.door{display:flex;flex-direction:column;align-items:flex-start;gap:.4rem;
  padding:1.3rem 1.4rem 1.2rem;border:1px solid var(--line);border-radius:12px;background:rgba(250,248,242,.55);
  text-decoration:none;transition:border-color .3s,box-shadow .35s,transform .35s var(--ease-spring),background .3s;
  min-height:9.5rem;
  /* it is a selector, not a link — button reset */
  font:inherit;color:inherit;text-align:left;width:100%;cursor:pointer;-webkit-appearance:none;appearance:none}
.door:hover,.door:focus-visible{border-color:var(--green);background:var(--paper);box-shadow:var(--shadow-deep);transform:translateY(-5px)}
.door__no{font-family:'IBM Plex Mono',monospace;color:var(--green);font-weight:600;font-size:var(--t-label);letter-spacing:.08em;white-space:nowrap}
.door__body{display:flex;flex-direction:column;gap:.25rem;flex:1}
.door__t{font-size:clamp(1.2rem,1.05rem + 0.5vw,1.5rem);font-weight:450;line-height:1.15;letter-spacing:-.01em;transition:color .3s;margin-bottom:.15rem}
.door__d{font-size:clamp(0.88rem,0.84rem + 0.15vw,0.95rem);color:var(--ink-2);line-height:1.48;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.door:hover .door__t,.door:focus-visible .door__t{color:var(--green-deep)}
/* the cards no longer travel anywhere, so no arrow promising that they do */
.door__go{display:none}
/* the lens noun binds the card to the floating lens control and to #lens= in the URL */
.door__kick{display:flex;align-items:baseline;gap:.55em;font-family:'IBM Plex Mono',monospace;
  font-size:var(--t-label);letter-spacing:.08em;white-space:nowrap}
.door__kick .door__no{color:var(--ink-3);opacity:.7}
.door__kick .door__who{color:var(--green);font-weight:600;text-transform:uppercase;letter-spacing:.14em}
.door.is-lens .door__kick .door__who{color:var(--green-deep)}
/* one line of plain language ahead of the choice, explaining what the choice does */
.doors__hint{font-size:clamp(0.88rem,0.84rem + 0.15vw,0.95rem);color:var(--ink-3);
  max-width:52ch;margin:-.35rem 0 .9rem;line-height:1.5}
/* a persistent state deserves a persistent confirmation, not a 2.4s toast */
.doors__note{margin-top:.95rem;font-size:var(--t-label);color:var(--ink-3);line-height:1.5;
  display:none;align-items:baseline;gap:.5em}
.doors__note.show{display:flex}
.doors__note b{font-weight:500;color:var(--ink-2)}
.doors__note::before{content:"";flex:none;width:5px;height:5px;margin-top:.55em;border-radius:50%;background:var(--green)}
.door:active{transform:scale(.975);transition-duration:.1s}
.proofstrip{margin-top:1.6vh;padding-top:1vh;border-top:1px solid var(--line);display:flex;flex-direction:column;gap:.5rem}
.proofstrip__creds{display:flex;flex-wrap:wrap;gap:.6rem var(--sp-2)}
.proofstrip__creds span{font-size:var(--t-label);color:var(--ink-3);display:inline-flex;align-items:center;gap:.5em}
.proofstrip__creds span::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--tint-dim)}
.proofstrip__clients{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .85rem}
.proofstrip__lab{font-size:clamp(0.875rem,0.7rem + 0.6vw,1.1rem);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3)}
.proofstrip__clients span:not(.proofstrip__lab){font-family:'Fraunces',serif;font-size:var(--t-body);font-weight:500;color:var(--ink-2)}

/* ---- manifold (shared spine visual) ---- */
.mf{position:relative}
.mf__svg{width:100%;height:auto}
.pipe-wall{fill:none;stroke:var(--line-strong);stroke-width:16;stroke-linecap:round}
.pipe-bore{fill:none;stroke:var(--paper);stroke-width:9;stroke-linecap:round}
.pipe-flow{fill:none;stroke:var(--green);stroke-width:5;stroke-linecap:round;stroke-dasharray:14 20;opacity:.9}
.drop{stroke:var(--line-strong);stroke-width:4;stroke-linecap:round}
.drop-flow{stroke:var(--green);stroke-width:2.5;stroke-linecap:round;stroke-dasharray:6 10;opacity:.85}
.node-ring{fill:var(--paper);stroke:var(--green);stroke-width:2.5}
.node-dot{fill:var(--green)}
.cap{stroke:var(--brown);stroke-width:3;stroke-linecap:round}
.seam-x{stroke:var(--brown);stroke-width:2.5;stroke-linecap:round}
.frag-wall{fill:none;stroke:var(--grey-deep);stroke-width:16;stroke-linecap:round;opacity:.55}
.frag-bore{fill:none;stroke:var(--paper);stroke-width:9;stroke-linecap:round}
.frag-flow{fill:none;stroke:var(--grey-deep);stroke-width:5;stroke-linecap:round;stroke-dasharray:12 16;opacity:.75}
.frag-drop{stroke:var(--grey-deep);stroke-width:4;stroke-linecap:round;opacity:.6}
.frag-ring{fill:var(--paper);stroke:var(--grey-deep);stroke-width:2.5}
.frag-dot{fill:var(--grey-deep)}
.layer-integrated,.layer-fragmented{transition:opacity .5s ease}
.mf-hero:not(.frag) .layer-fragmented{opacity:0;pointer-events:none}
.mf-hero.frag .layer-integrated{opacity:0;pointer-events:none}
@keyframes flow{to{stroke-dashoffset:-680}}
@keyframes flowdrop{to{stroke-dashoffset:-64}}
@keyframes flowfrag{0%{stroke-dashoffset:0}55%{stroke-dashoffset:-84}100%{stroke-dashoffset:-84}}
.mf-hero:not(.frag) .pipe-flow,.mf-svc .pipe-flow{animation:flow 9s linear infinite}
.mf-hero:not(.frag) .drop-flow,.mf-svc .drop-flow{animation:flowdrop 2.2s linear infinite}
.mf-hero.frag .frag-flow{animation:flowfrag 3.4s ease-in-out infinite}

.mf__controls{display:flex;flex-wrap:wrap;align-items:center;gap:1rem 1.6rem;margin-bottom:1.2rem}
.toggle{display:inline-flex;padding:.3rem;border-radius:999px;background:var(--card);border:1px solid var(--line);position:relative}
.toggle__btn{position:relative;z-index:2;padding:.55rem 1.1rem;border-radius:999px;font-size:var(--t-label);font-weight:600;
  color:var(--ink-2);transition:color .35s var(--ease);white-space:nowrap}
.toggle__btn[aria-pressed="true"]{color:var(--paper)}
.toggle__pill{position:absolute;z-index:1;top:.3rem;bottom:.3rem;border-radius:999px;background:var(--green);
  transition:left .45s var(--ease),width .45s var(--ease),background .45s;box-shadow:0 4px 14px rgba(63,95,60,.28)}
.mf-hero.frag .toggle__pill{background:var(--grey-deep)}
.readout{display:flex;gap:1.4rem;flex-wrap:wrap;margin-left:auto}
.stat{display:flex;flex-direction:column;gap:.1rem;min-width:4.6rem}
.stat__v{font-family:'Fraunces',serif;font-optical-sizing:auto;font-size:var(--t-h4);font-weight:400;line-height:1;
  color:var(--green-deep);transition:color .4s}
.mf-hero.frag .stat__v{color:var(--brown)}
.stat__l{color:var(--ink-3);font-size:var(--t-caption)}

/* service index — five boxed lines that assemble into one connected run */
.svcidx{position:relative;margin-top:var(--sp-4)}
.svcidx__rule,.svcidx__flow{display:none}
.rail{display:grid;grid-template-columns:repeat(5,1fr);gap:2.2rem;position:relative;align-items:stretch}
.outlet{position:relative;display:flex;flex-direction:column;align-items:flex-start;text-align:left;gap:.45rem;
  min-height:8.6rem;padding:1.05rem 1.05rem 1.15rem;background:var(--paper);border:1px solid var(--line-strong);border-radius:12px;
  cursor:pointer;transition:transform 1.15s var(--ease),opacity .9s var(--ease),
    border-color .3s,background .3s,box-shadow .3s}
/* connector bridging each box to the previous one */
.outlet:not(:first-child)::before{content:"";position:absolute;top:50%;right:100%;width:2.2rem;height:2px;
  transform:translateY(-50%) scaleX(1);transform-origin:right;background:var(--line-strong);
  transition:transform .9s var(--ease),background .35s}
.outlet:not(:first-child)::after{content:"";position:absolute;top:50%;left:-1.1rem;width:7px;height:7px;border-radius:50%;
  transform:translate(-50%,-50%);background:var(--grey);box-shadow:0 0 0 3px var(--paper);pointer-events:none;
  transition:background .35s,box-shadow .35s}
.outlet__num{font-family:'Fraunces',serif;font-optical-sizing:auto;font-style:italic;font-size:var(--t-h3);line-height:1;
  color:var(--ink-3);transition:color .35s}
.outlet__node{display:none}
.outlet__name{margin-top:.1rem;font-family:'Fraunces',serif;font-optical-sizing:auto;font-size:var(--t-body);line-height:1.15;
  font-weight:400;color:var(--ink);text-wrap:balance;transition:color .35s;min-height:2.3em}
.outlet__tag{margin-top:auto}
.outlet__tag{font-family:'IBM Plex Mono',monospace;font-size:var(--t-caption);font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--brown);opacity:.8}
/* hover / active highlight (shadow, not transform) */
.outlet:hover,.outlet:focus-visible{border-color:var(--green);background:rgba(90,135,85,.05);
  box-shadow:0 10px 26px -16px rgba(46,64,43,.55)}
.outlet.is-active{border-color:var(--green);background:rgba(90,135,85,.06);
  box-shadow:0 8px 24px -15px rgba(46,64,43,.5)}
.outlet:hover .outlet__num,.outlet:focus-visible .outlet__num,.outlet.is-active .outlet__num{color:var(--green-deep)}
.outlet.is-active .outlet__name{color:var(--green-deep)}
/* the run lights up to the box you're on */
.outlet.is-lit::before{background:var(--green)}
.outlet.is-lit::after{background:var(--green);box-shadow:0 0 0 3px var(--paper),0 0 0 7px rgba(90,135,85,.16)}
/* scatter → assemble entrance */
.rail:not(.rail--split).anim .outlet{opacity:0}
.rail:not(.rail--split).anim .outlet:nth-child(1){transform:translate(-46px,24px) rotate(-5deg) scale(.9)}
.rail:not(.rail--split).anim .outlet:nth-child(2){transform:translate(-12px,56px) rotate(3.5deg) scale(.88)}
.rail:not(.rail--split).anim .outlet:nth-child(3){transform:translate(0,-48px) rotate(-3deg) scale(.88)}
.rail:not(.rail--split).anim .outlet:nth-child(4){transform:translate(12px,54px) rotate(4deg) scale(.88)}
.rail:not(.rail--split).anim .outlet:nth-child(5){transform:translate(46px,26px) rotate(5deg) scale(.9)}
.rail:not(.rail--split).anim .outlet::before{transform:translateY(-50%) scaleX(0)}
.rail:not(.rail--split).anim.is-assembled .outlet{opacity:1;transform:none}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(1){transition-delay:.05s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(2){transition-delay:.25s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(3){transition-delay:.45s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(4){transition-delay:.65s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(5){transition-delay:.85s}
.rail:not(.rail--split).anim.is-assembled .outlet::before{transform:translateY(-50%) scaleX(1)}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(2)::before{transition-delay:2.0s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(3)::before{transition-delay:2.2s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(4)::before{transition-delay:2.4s}
.rail:not(.rail--split).anim.is-assembled .outlet:nth-child(5)::before{transition-delay:2.6s}
/* while pointing at one box, ease the others back (after assembly only) */
.rail:not(.rail--split).is-assembled:hover .outlet:not(:hover){opacity:.5}
/* reaching the last box completes the whole run — light every box */
.rail:not(.rail--split).all-lit .outlet{border-color:var(--green);background:rgba(90,135,85,.05)}
.rail:not(.rail--split).all-lit .outlet__num{color:var(--green-deep)}
.rail:not(.rail--split).all-lit .outlet::before{background:var(--green)}
.rail:not(.rail--split).all-lit .outlet::after{background:var(--green);box-shadow:0 0 0 3px var(--paper),0 0 0 7px rgba(90,135,85,.16)}
.rail:not(.rail--split).all-lit:hover .outlet:not(:hover){opacity:1}

/* ===== services index — bare typographic spine + a single stage card =====
   The index is deliberately NOT a card. It's a hairline-delimited list sitting
   in the margin, using the same rule treatment as .subs inside the stage, so
   the two panes rhyme structurally instead of competing as two boxes.
   It also no longer stretches: the spine's geometry is fixed, so hovering
   across it can never resize it. Only the stage responds. */
.svcsplit{--svc-row:4.9rem;
  display:grid;grid-template-columns:minmax(13rem,17rem) 1fr;gap:2.2rem;align-items:stretch}

.rail.rail--split{display:flex;flex-direction:column;height:auto;
  background:none;border:0;border-radius:0;overflow:visible}

/* Rows are a fixed height and a two-item flex, centred on the cross axis.
   Deliberately NOT a grid: the previous construction used auto tracks, an
   align-content:center, and a numeral spanning both rows, and the result was
   row 1 rendering 27px shorter than the rest with the text of rows 2-5 sitting
   ~13px below centre. Nothing here is content-dependent, so all five rows are
   identical by construction. */
.rail--split .outlet{position:relative;flex:none;
  display:flex;flex-direction:row;align-items:center;gap:.85rem;
  width:100%;height:var(--svc-row);min-height:0;padding:0 1.8rem 0 1rem;
  background:none;border:0;border-bottom:1px solid var(--line);border-radius:0;
  box-shadow:none !important;cursor:pointer;text-align:left;
  transition:border-color .3s var(--ease)}
.rail--split .outlet__txt{display:flex;flex-direction:column;gap:.2rem;min-width:0;flex:1 1 auto}
.rail--split .outlet:first-child{border-top:1px solid var(--line)}
.rail--split .outlet:last-child{border-bottom:1px solid var(--line)}
.rail--split .outlet:hover,.rail--split .outlet:focus-visible{border-bottom-color:var(--line-strong)}
/* darken the rule above the hovered row too, so it reads as bracketed.
   Progressive enhancement — no :has() support just means one rule instead of two. */
.rail--split .outlet:has(+ .outlet:hover),
.rail--split .outlet:has(+ .outlet:focus-visible){border-bottom-color:var(--line-strong)}

/* active marker: an editorial change-bar in the margin, not a fill.
   height/right are explicit resets — the base .outlet connector rules set
   height:2px and right:100%, which otherwise collapse this to a dash. */
.rail--split .outlet::before{content:"";position:absolute;left:0;right:auto;
  top:.85rem;bottom:.85rem;height:auto;width:2px;
  background:transparent;border-radius:0;transform:none;
  transition:background .3s var(--ease)}
.rail--split .outlet.is-active::before{background:var(--green)}

/* leader arrow sits past the text margin, table-of-contents style */
.rail--split .outlet::after{content:"\2192";position:absolute;left:auto;right:.2rem;top:50%;
  width:auto;height:auto;border-radius:0;background:none;box-shadow:none;
  transform:translate(-5px,-50%);color:var(--green);
  font-family:'IBM Plex Mono',monospace;font-size:var(--t-body);opacity:0;
  transition:opacity .25s var(--ease),transform .25s var(--ease)}
.rail--split .outlet:hover::after,.rail--split .outlet:focus-visible::after,
.rail--split .outlet.is-active::after{opacity:1;transform:translate(0,-50%)}

/* numeral: nudged up — an italic Fraunces figure sits optically low in its em box */
.rail--split .outlet__num{flex:0 0 2.3rem;
  font-size:var(--t-h4);line-height:1;color:var(--ink-3);
  font-variant-numeric:tabular-nums;transform:translateY(-.055em);
  transition:color .3s var(--ease)}
/* min-height:0 resets the base rule's 2.3em, which was forcing extra height */
.rail--split .outlet__name{margin:0;min-height:0;line-height:1.2;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:color .3s var(--ease)}
.rail--split .outlet__tag{margin:0;line-height:1.3;
  opacity:.75;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:opacity .3s var(--ease),color .3s var(--ease)}

.rail--split .outlet:hover .outlet__num,.rail--split .outlet:focus-visible .outlet__num{color:var(--green)}
.rail--split .outlet:hover .outlet__name,.rail--split .outlet:focus-visible .outlet__name{color:var(--green-deep)}
.rail--split .outlet:hover .outlet__tag,.rail--split .outlet:focus-visible .outlet__tag{opacity:1}
.rail--split .outlet.is-active .outlet__num{color:var(--green)}
.rail--split .outlet.is-active .outlet__name{color:var(--green-deep)}
.rail--split .outlet.is-active .outlet__tag{opacity:1}

/* entrance: rows settle in from the left, staggered */
.rail--split.anim .outlet{opacity:0;transform:translateX(-14px)}
.rail--split.anim.is-assembled .outlet{opacity:1;transform:none;
  transition:opacity .55s var(--ease),transform .55s var(--ease),border-color .3s var(--ease)}
.rail--split.anim.is-assembled .outlet:nth-child(1){transition-delay:.03s}
.rail--split.anim.is-assembled .outlet:nth-child(2){transition-delay:.09s}
.rail--split.anim.is-assembled .outlet:nth-child(3){transition-delay:.15s}
.rail--split.anim.is-assembled .outlet:nth-child(4){transition-delay:.21s}
.rail--split.anim.is-assembled .outlet:nth-child(5){transition-delay:.27s}


/* services stage — always visible, content cross-fades on hover/select */
.mf-svc{margin-top:var(--sp-3)}
/* stage — the only card in the section. It stretches to the grid row, which is
   whichever is taller: the spine (5 fixed rows) or the stage's own content. So
   the card always spans the full sidebar, and the spine's rows never resize.
   Top padding runs lighter than the bottom so the eyebrow's first line sits on
   roughly the same optical line as the spine's first service name. */
.drawer{display:flex;flex-direction:column;position:relative;
  background:var(--card);border:1px solid var(--line);border-radius:16px;
  padding:1.5rem 2.4rem 2.2rem;opacity:1;transition:opacity .16s ease}
.drawer.is-swap{opacity:0}
/* speech-bubble tail: points back at whichever rail row is selected, so the
   panel reads as that row's content rather than an unrelated floating card.
   --tail-top is set in JS (measured px, not assumed row height) so it stays
   correct regardless of font-scale, breakpoint, or content-driven row height. */
.drawer::before,.drawer::after{content:"";position:absolute;top:var(--tail-top,50%);
  transform:translateY(-50%);clip-path:polygon(100% 0,100% 100%,0 50%);
  transition:top .32s var(--ease)}
.drawer::before{left:-15px;width:16px;height:25px;background:var(--line-strong)}
.drawer::after{left:-13px;width:14px;height:21px;background:var(--card)}
@media(max-width:1024px){.drawer::before,.drawer::after{display:none}}
/* φ (1.618) — the same ratio the type scale is built on.
   flex:1 makes the grid fill the stretched card, which is what gives the
   bottom-pinned CTA a real bottom to sit on. */
.drawer__grid{display:grid;grid-template-columns:1fr 1.618fr;gap:2.4rem;
  align-items:stretch;flex:1}
/* left column runs full height so the CTA can sit on the card's bottom line,
   squaring off against the end of the sub list */
.drawer__grid>div:first-child{display:flex;flex-direction:column}
.drawer__code{color:var(--green);margin-bottom:.7rem}
.drawer__title{font-family:'Fraunces',serif;font-optical-sizing:auto;font-size:clamp(1.272rem,1.1rem + 1.2vw,2.058rem);
  font-weight:400;line-height:1.08;letter-spacing:-.01em}
.drawer__lede{color:var(--ink-2);margin-top:.8rem;margin-bottom:1.6rem;max-width:44ch}
.subs{list-style:none;display:flex;flex-wrap:wrap;gap:.6rem;justify-content:center}
.sub{border:1px solid var(--line);border-radius:999px;padding:.55rem 1.1rem;
  font-size:var(--t-caption);color:var(--ink-2);background:var(--paper);
  transition:border-color .25s var(--ease),color .25s var(--ease)}
.sub:hover{border-color:var(--green);color:var(--green-deep)}
/* margin-top:auto pins the button to the card's bottom line; .drawer__lede's
   margin-bottom guarantees the gap never closes when the copy runs long */
.drawer .btn{margin-top:auto;flex:none;align-self:flex-start}

/* ===== services scatter (What We Do) ====================================
   Static elliptical layout — each node is placed directly at a left/top
   percentage computed from its angle (JS below), rather than centered in a
   rotated square ring. That decouples horizontal spread from vertical
   span: the stage is now wider than it is tall (aspect-ratio), so the same
   angle math reads as a flattened ellipse instead of a full circle,
   keeping the section shorter without bunching the nodes together. The
   dashed guide ring in the SVG layer stretches to match automatically
   (its viewBox has preserveAspectRatio="none").
   Lighting: hub and nodes are shaded with a shifted-highlight radial
   gradient (bright spot upper-left, darkening toward the limb) plus a
   small blurred specular pseudo-element — the two-gradient technique used
   for CSS "sphere" effects — rather than a flat tinted circle. */
.orbit{position:relative;width:100%;max-width:1120px;aspect-ratio:1.7/1;margin:0 auto var(--sp-4)}
.orbit__lines{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none}
.orbit__lines circle.path{fill:none;stroke:var(--line-strong);stroke-width:.4;
  stroke-dasharray:.4 2.2;opacity:.55}

/* plain paper hub — the green "glossy sphere" version was reading as too
   much colour weight for a piece that's mostly just a mounting plate for the
   logo badge; stripped the gradient, grain, ambient glow bloom and specular
   dot back out, keeping only the two-tone rim (paper, then brown) as the
   one bit of definition separating the hub from the badge sitting on it.
   A soft green glow sits just outside that brown rim — an extra blurred
   box-shadow layer beyond the two solid ones — so the ring itself reads
   as gently lit rather than a flat hard edge against the orbit stage. */
.orbit__hub{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:clamp(220px,25vw,320px);height:clamp(220px,25vw,320px);border-radius:50%;z-index:1;
  background:var(--card);overflow:hidden;
  box-shadow:0 0 0 6px var(--card),0 0 0 9px var(--brown),
    0 0 22px 4px rgba(90,135,85,.4),var(--shadow-deep);
  display:flex;align-items:center;justify-content:center;text-align:center;padding:clamp(18px,3.2vw,26px)}
/* Hands photo sits behind the logo badge, filling the hub circle — cover +
   center works cleanly since the source is already square, matching the
   hub's own aspect ratio 1:1. */
.orbit__hub__photo{position:absolute;inset:0;background-size:cover;background-position:center;z-index:0}
/* Dark scrim over the photo so the green/brown logo keeps enough contrast
   to read clearly against a busy photographic background rather than the
   plain paper it sat on before. */
.orbit__hub__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(circle at 50% 50%,rgba(20,22,16,.4),rgba(20,22,16,.62))}
/* Soft paper "plate" feathered behind the badge — the scrim alone still left
   the logo fighting a busy photo underneath it; this gives the mark its own
   quiet patch of light to sit on (matching the ellipse of the wordmark
   itself) so it reads clearly regardless of what's happening in the photo,
   while still letting the photo show through at the rim of the hub. */
.orbit__hub__plate{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(ellipse 68% 46% at 50% 50%,rgba(250,248,242,.96) 0%,
    rgba(250,248,242,.88) 45%,rgba(250,248,242,.3) 72%,rgba(250,248,242,0) 88%)}
.orbit__hub__badge{position:relative;z-index:2;width:84%}
.orbit__hub__badge svg{width:100%;height:auto;display:block}
.orbit__ring{position:absolute;inset:0}
.orbit__ring.anim .orbit__path{opacity:0;transition:opacity .5s var(--ease)}
.orbit__ring.anim.is-assembled .orbit__path{opacity:1}
.orbit__ring.anim.is-assembled .orbit__path:nth-child(1){transition-delay:.04s}
.orbit__ring.anim.is-assembled .orbit__path:nth-child(2){transition-delay:.11s}
.orbit__ring.anim.is-assembled .orbit__path:nth-child(3){transition-delay:.18s}
.orbit__ring.anim.is-assembled .orbit__path:nth-child(4){transition-delay:.25s}
.orbit__ring.anim.is-assembled .orbit__path:nth-child(5){transition-delay:.32s}

/* each node is placed at an explicit --x/--y percentage (computed in JS
   from its angle and radius) rather than rotated into position — this is
   what lets the layout be an ellipse (wide, short) instead of forcing a
   true circle. */
.orbit__path{position:absolute;left:var(--x);top:var(--y);z-index:2;
  transform:translate(-50%,-50%)}
.orbit__spin{position:relative;width:var(--s);height:var(--s)}
.orbit__node{position:relative;width:100%;height:100%}
.orbit__node__inner{width:100%;height:100%;border-radius:50%;position:relative;overflow:hidden;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;
  background:radial-gradient(125% 125% at 32% 24%,#ffffff 0%,var(--paper) 42%,var(--card) 78%,var(--line-strong) 130%);
  border:1px solid var(--line);cursor:pointer;text-align:center;
  /* the feathered-glow read from the reference: a thin bright paper ring right
     at the edge, then a soft green bloom bleeding past it before it meets the
     page. box-shadow paints on the border-box, so it isn't clipped by this
     element's own overflow:hidden (which only clips the photo/children) —
     the halo and the circular photo crop coexist for free. */
  box-shadow:0 0 0 1px rgba(255,255,255,.9),0 0 22px 4px rgba(var(--node-accent-rgb,122,168,96),.4),
    0 10px 22px rgba(20,40,26,.14),inset 0 1px 0 rgba(255,255,255,.7);
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease),transform .3s var(--ease)}
/* the service photo — reuses the site's existing duotone .photo pipeline
   (loadPhoto/--duo/--sat), just masked to the circle and with its own
   sphere-shading shadow baked on so it reads as lit rather than pasted on.
   Sits UNDER the icon/tag; while it's unloaded (opacity:0, no asset yet,
   or the asset simply doesn't exist), the gradient sphere + icon above is
   the entire visible result — nothing breaks if a photo is never supplied. */
.orbit__node__inner .photo{border-radius:50%;z-index:1;
  box-shadow:inset 0 -10px 16px rgba(8,20,10,.4),inset 0 6px 10px rgba(255,255,255,.3),
    inset 0 0 22px 4px rgba(20,40,20,.22)}
/* rim-only tint, replacing a flat full-circle duotone: the centre of the
   photo (where the subject sits — a truck, a meter, a trench) stays close to
   true colour so it still reads as documentary, while the outer 55% of the
   circle deepens into the brand green. This is the single biggest lever for
   the "reference" look — an even tint across the whole photo just muddies
   the subject, a vignette tint makes the same photo feel unified AND alive. */
.orbit__node__inner .photo::after{
  background:radial-gradient(circle at 50% 46%,transparent 40%,var(--node-accent,var(--green)) 100%);
  mix-blend-mode:color;opacity:.68}
/* fine grain — a tiled turbulence noise, blended in overlay mode at very low
   opacity. This is what stops the green from looking like a flat vector fill
   and gives it the mossy, organic texture the reference photo has. One
   shared data-URI, so it costs nothing extra to repeat across every node. */
.orbit__node__inner::before{content:"";position:absolute;inset:0;z-index:2;border-radius:50%;
  pointer-events:none;mix-blend-mode:overlay;opacity:.5;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.14 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>")}
/* once a photo actually loads, the abstract line-icon steps aside — the
   photo is the identifier now — and the tag label gets a small dark scrim
   so it stays legible sitting on top of a real image instead of a flat tint */
.orbit__node__inner .photo.is-loaded ~ .orbit__icon{display:none}
.orbit__node__inner .photo.is-loaded ~ .orbit__tag{color:#fff;background:rgba(18,28,20,.46);
  border-radius:999px;padding:.22em .65em;text-shadow:0 1px 3px rgba(0,0,0,.4)}
/* the specular highlight — tightened and brightened from a soft shading blob
   into a small sharp glass hotspot, the way light actually catches a curved
   surface rather than diffusing evenly across it */
.orbit__node__inner::after{content:"";position:absolute;top:9%;left:16%;width:26%;height:16%;
  border-radius:50%;background:radial-gradient(circle,rgba(255,255,255,.95),rgba(255,255,255,0) 68%);
  filter:blur(.5px);pointer-events:none;z-index:3}
/* when there's no photo yet, the flat line-icon needs its own bit of pop —
   a soft drop shadow gives it a "sticker" lift off the gradient sphere
   instead of sitting flush and flat against it */
.orbit__node__inner .orbit__icon svg{filter:drop-shadow(0 2px 3px rgba(20,40,20,.32))}
.orbit__node__inner .orbit__icon{width:2.6rem;height:2.6rem;line-height:1;position:relative;z-index:2;
  transition:color .3s var(--ease)}
.orbit__node__inner .orbit__icon svg{width:100%;height:100%;display:block}
.orbit__node__inner .orbit__tag{font-size:.9rem;font-weight:600;line-height:1.2;color:var(--ink-2);
  padding:0 .4rem;position:relative;z-index:2;transition:color .3s var(--ease),background .3s var(--ease)}
/* selection reads as a ring around the circle plus a small lift, not a fill —
   the circle itself never permanently changes colour. Hovering (or the ring
   it sits on being hovered) also pauses the orbit — see the :hover rule
   below — so picking a moving target never turns into a chase. */
.orbit__node:hover .orbit__node__inner,.orbit__node__inner:focus-visible{
  border-color:var(--node-accent,var(--green));
  box-shadow:0 0 0 1px rgba(255,255,255,.95),0 0 34px 8px rgba(var(--node-accent-rgb,122,168,96),.55),
    0 14px 26px rgba(20,40,26,.2),inset 0 1px 0 rgba(255,255,255,.7);
  transform:translateY(-3px)}
.orbit__node.is-active .orbit__node__inner{border-color:var(--node-accent,var(--green));
  box-shadow:0 0 0 4px rgba(var(--node-accent-rgb,90,135,85),.26),0 0 30px 6px rgba(var(--node-accent-rgb,122,168,96),.46),
    0 14px 26px rgba(20,40,26,.18)}
.orbit__node.is-active .orbit__tag{color:var(--node-accent,var(--green-deep))}
/* the click feedback itself: a quick pop, not a lasting state change */
@keyframes orbitPop{0%{transform:scale(1)}45%{transform:scale(1.22)}100%{transform:scale(1)}}
.orbit__node__inner.is-popping{animation:orbitPop .45s var(--ease)}

@media (max-width:900px){
  /* Option C: drop the strip entirely below 900px. It was fighting the
     format — ellipses overlapping with clipped text, low-contrast labels
     on busy photo crops (see the mobile screenshot review). The accordion
     below already reads clean at this width, so it becomes the only nav;
     the orbit stays exactly as-is for tablet/desktop above this breakpoint. */
  .mf-svc{display:none}
  .svc-explore{margin:var(--sp-2) auto 0}
}


/* ===== svc explore accordion — the full per-line descriptions that used to
   live inside the orbit drawer. Circles stay a quick scan; anyone who wants
   the paragraph-level detail scrolls here instead of it arriving unasked. */
.svc-explore{max-width:760px;margin:0 auto}
.svc-acc__item{border-bottom:1px solid var(--line)}
.svc-acc__item:first-child{border-top:1px solid var(--line)}
.svc-acc__head{width:100%;display:flex;align-items:center;gap:1rem;
  padding:1.1rem 0;background:none;border:0;cursor:pointer;text-align:left;color:inherit;
  font-family:inherit}
.svc-acc__code{font-family:'IBM Plex Mono',monospace;font-size:.7rem;color:var(--green);
  flex:none;width:3.6rem}
/* small icon circle, reusing the same line-icon set the desktop orbit uses
   (see ICONS in the script below) so identity carries over even though the
   strip itself no longer renders on mobile */
.svc-acc__ic{flex:none;width:1.9rem;height:1.9rem;border-radius:50%;background:var(--card);
  display:flex;align-items:center;justify-content:center}
.svc-acc__ic svg{width:1.05rem;height:1.05rem;display:block}
.svc-acc__name{flex:1;font-family:'Fraunces',serif;font-optical-sizing:auto;
  font-size:clamp(1rem,.9rem + .4vw,1.18rem);line-height:1.25}
.svc-acc__chev{flex:none;width:1.4rem;height:1.4rem;border-radius:50%;border:1px solid var(--line-strong);
  display:flex;align-items:center;justify-content:center;font-size:.9rem;color:var(--ink-2);
  transition:transform .3s var(--ease),border-color .3s var(--ease);position:relative}
.svc-acc__item.is-open .svc-acc__chev{transform:rotate(45deg);border-color:var(--green);color:var(--green-deep)}
.svc-acc__body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .4s var(--ease)}
.svc-acc__item.is-open .svc-acc__body{grid-template-rows:1fr}
.svc-acc__panel{overflow:hidden}
.svc-acc__lede{color:var(--ink-2);font-size:var(--t-body);max-width:58ch;padding-bottom:.4rem}
.svc-acc__subs{list-style:none;padding-bottom:1rem}
.svc-acc__subs li{padding:.7rem 0;border-top:1px solid var(--line);display:grid;
  grid-template-columns:2rem 1fr;column-gap:.6rem;row-gap:.15rem}
.svc-acc__k{font-family:'IBM Plex Mono',monospace;font-size:.66rem;color:var(--green);grid-row:1}
.svc-acc__n{font-weight:600;font-size:var(--t-caption);grid-column:2;grid-row:1}
.svc-acc__d{grid-column:2;grid-row:2;color:var(--ink-2);font-size:.82rem;line-height:1.5}
.svc-acc__panel .btn{margin-bottom:1.3rem}
@media (max-width:620px){
  .svc-acc__name{font-size:1rem}
  .svc-acc__subs li{grid-template-columns:1.6rem 1fr}
  /* icon + code + name + chevron with a 1rem gap on every pair eats too
     much of a narrow phone's width before the label even starts — tighten
     the row gap and shrink the code column since it's secondary info */
  .svc-acc__head{gap:.6rem}
  .svc-acc__code{width:2.6rem;font-size:.62rem}
}
@media (prefers-reduced-motion:reduce){ .svc-acc__body{transition-duration:.01ms} }
