/* ============================================================
   mm-style.css — MindMarket-inspired hero + nav layer
   ------------------------------------------------------------
   Loaded AFTER assets/css/styles.css. Everything here is additive
   or an override; removing the <link> restores the previous look.

   Palette stays GreenSilicon (sage/cream/ink). Structure, type
   scale and motion come from the MindMarket reference.
   ============================================================ */

:root {
  --mm-font: 'Inter', system-ui, -apple-system, sans-serif;
  /* styles.css points every display heading at --font-display (Instrument
     Sans). Redefining both here — mm-style.css loads later — switches the
     whole site to Inter without touching the original stylesheet. */
  --font: 'Inter', system-ui, -apple-system, sans-serif;
  --font-display: 'Inter', system-ui, -apple-system, sans-serif;
  --mm-green: #B3E29C;          /* GS sage — hero block */
  --mm-green-deep: #9FD486;     /* shade for path/inner shapes */
  --mm-cream: #EFEBDE;
  --mm-ink: #1C1E18;
  --mm-radius: 40px;
  --mm-nav-h: 68px;   /* measured off the reference bar */
  --mm-ease: cubic-bezier(.16, 1, .3, 1);
}

/* ── TYPE ──────────────────────────────────────────────── */
body,
body button,
body input,
body textarea,
body select {
  font-family: var(--mm-font);
}

body {
  background: var(--mm-cream);
}

/* ============================================================
   FLOATING PILL NAV
   The existing markup (body>nav > .nav-logo + ul.nav-center +
   .nav-mobile-toggle) is preserved so the mega-menu JS in main.js
   keeps working. Only the chrome changes.
   ============================================================ */
body > nav {
  height: auto;
  padding: 18px 24px 0;
  background: transparent !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  border-bottom: none !important;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 14px;
  pointer-events: none;
}

body > nav.scrolled {
  background: transparent !important;
  backdrop-filter: none !important;
  border-bottom: none !important;
}

/* The bar itself. A real element rather than a ::before, so the quote
   button beside it is a genuinely separate pill instead of something
   positioned off this one's geometry. Built by mm-hero.js. */
.nav-shell {
  pointer-events: auto;
  flex: 1 1 auto;
  max-width: 1000px;
  min-width: 0;
  height: var(--mm-nav-h);
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 14px 0 22px;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 6px 24px rgba(28, 30, 24, .09);
  transition: box-shadow .4s var(--mm-ease);
}

body > nav.scrolled .nav-shell {
  box-shadow: 0 10px 34px rgba(28, 30, 24, .14);
}

/* logo sits at the left of the bar, in normal flow */
body > nav .nav-logo {
  position: static;
  height: auto;
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}

body > nav .nav-logo img {
  /* logo-mark.png is cropped to the glyph (186x131). The old asset was a
     360x360 canvas whose mark filled only 31% of the height, so a 42px
     box rendered a ~13px mark. Same box now renders the mark full size. */
  height: 40px;
  width: auto;
}

@media (max-width: 768px) {
  body > nav .nav-logo img { height: 32px; }
}

/* links pushed to the right end of the bar */
body > nav .nav-center {
  position: static;
  left: auto;
  transform: none;
  height: auto;
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0 0 0 auto;
  list-style: none;
  padding: 0;
}

body > nav .nav-item > a {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 12px 17px;
  border-radius: 999px;
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -.01em;
  white-space: nowrap;
  transition: background .25s var(--mm-ease), color .25s;
}

body > nav .nav-item > a:hover,
body > nav .nav-item.active > a {
  background: #EFF6E4;
}

body > nav .nav-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--mm-green);
  opacity: 0;
  transform: scale(.4);
  transition: opacity .3s, transform .3s var(--mm-ease);
}

body > nav .nav-item > a:hover .nav-dot,
body > nav .nav-item.active .nav-dot {
  opacity: 1;
  transform: scale(1);
}

/* mega menu hangs below the pill */
body > nav .mega-menu {
  top: calc(100% + 14px);
  border-radius: 22px;
  box-shadow: 0 14px 54px rgba(28, 30, 24, .14);
}

/* "Get a quote" pill, injected by mm-hero.js */
.nav-cta {
  pointer-events: auto;
  flex: 0 0 auto;
  height: var(--mm-nav-h);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px 0 26px;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 6px 24px rgba(28, 30, 24, .09);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--mm-ink);
  transition: transform .35s var(--mm-ease);
}

.nav-cta:hover {
  transform: scale(1.035);
}

.nav-cta-badge {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--mm-green);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform .45s var(--mm-ease);
}

.nav-cta:hover .nav-cta-badge {
  transform: rotate(-14deg);
}

.nav-cta-badge svg {
  width: 19px;
  height: 19px;
}

@media (max-width: 1180px) {
  .nav-cta { display: none; }
}

/* mobile: pill shrinks to logo + burger.
   Breakpoint must match styles.css (.nav-mobile-toggle appears at <=768px). */
@media (max-width: 768px) {
  body > nav { padding: 18px 16px 0; }

  .nav-shell {
    flex: 1 1 auto;
    max-width: none;
    padding: 0 10px 0 18px;
  }

  /* burger sits at the right end of the bar, in flow */
  body > nav .nav-mobile-toggle {
    position: static;
    margin-left: auto;
    height: auto;
  }

  /* the menu is a fixed panel, so it escapes the shell cleanly */
  body > nav .nav-center {
    position: fixed;
    top: calc(18px + var(--mm-nav-h) + 10px);
    width: calc(100% - 32px);
    left: 16px;
    border-radius: 22px;
    height: auto;
    background: #fff;
    box-shadow: 0 14px 44px rgba(28, 30, 24, .16);

    /* The blanket `pointer-events: auto` further up this file was also hitting
       the COLLAPSED menu, leaving an invisible 330x304 panel over the hero
       that swallowed taps (elementFromPoint returned a hidden nav link).
       State it explicitly per state instead. */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .3s var(--mm-ease), transform .3s var(--mm-ease),
                visibility 0s linear .3s;
  }

  body > nav .nav-center.mobile-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
    transition: opacity .3s var(--mm-ease), transform .3s var(--mm-ease),
                visibility 0s;
  }
}

/* ============================================================
   COLOUR-BLOCK HERO
   ============================================================ */
.hero.mm-hero {
  min-height: 70vh;
  background: var(--mm-green);
  border-radius: 0 0 var(--mm-radius) var(--mm-radius);
  padding: clamp(150px, 17vh, 190px) 24px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  overflow: hidden;
  position: relative;
}

.mm-hero .hero-content {
  /* Art-directed frame, measured on a 2000x1300 reference:
     952px wide, centred on 1000px, block starting ~398px down.
     Expressed proportionally so it holds at other sizes. */
  max-width: 952px;
  margin-inline: auto;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  z-index: 3;
}

.mm-hero .hero-title {
  /* Metrics matter here: at display sizes a .95 line-height clips
     descenders against the line below, and -.05em tracking closes the
     word gaps entirely — worst where an italic accent meets roman text.
     These values stay tight without colliding. */
  /* Measured off mindmarket.com: Inter 500, -0.06em, line-height 0.95.
     Safe to run this tight now that .split-parent no longer clips
     descenders. word-spacing offsets the negative tracking so words
     keep a readable gap. */
  font-family: var(--mm-font);
  /* 8.1vw = 162px at the 2000px reference, which puts ~10-11 characters
     on a line inside the 952px measure — the same rhythm as the reference. */
  font-size: clamp(2.4rem, 8.1vw, 10.2rem);
  font-weight: 500;
  font-optical-sizing: auto;
  letter-spacing: -.055em;
  word-spacing: .06em;
  line-height: .97;
  color: var(--mm-ink);
  max-width: 100%;
  margin-bottom: 0;
  padding-bottom: .1em;        /* descender room */
  text-wrap: balance;          /* avoids one orphaned word on a line */
  overflow-wrap: break-word;
}

/* italics lean into whatever follows them — give them their own
   tracking and a trailing sliver so words never touch */
.mm-hero .hero-title .hero-accent,
.mm-hero .hero-title em,
.mm-hero .hero-title i {
  font-style: italic;
  letter-spacing: -.018em;
  padding-right: .07em;
}

/* long three-line headings need a little more restraint */

.mm-hero-sub {
  margin-top: clamp(24px, 3.4vh, 40px);
  font-size: clamp(1.05rem, 1.9vw, 1.6rem);
  font-weight: 500;
  letter-spacing: -.02em;
  color: rgba(28, 30, 24, .78);
}

.mm-hero .hero-btns {
  justify-content: center;
  margin-top: clamp(26px, 3.4vh, 38px);
}

/* pill button in the MindMarket shape */
.mm-hero .btn-dark,
.btn-mm {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  background: #fff;
  color: var(--mm-ink);
  border-radius: 16px;
  padding: 10px 10px 10px 22px;
  font-size: .97rem;
  font-weight: 600;
  letter-spacing: -.01em;
  box-shadow: 0 4px 18px rgba(28, 30, 24, .09);
  transition: transform .35s var(--mm-ease), box-shadow .35s;
}

.mm-hero .btn-dark:hover,
.btn-mm:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 12px 30px rgba(28, 30, 24, .16);
  opacity: 1;
}

.mm-hero .btn-dark .arr,
.btn-mm .arr {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--mm-green);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .95rem;
  transition: transform .3s var(--mm-ease);
}

.mm-hero .btn-dark:hover .arr,
.btn-mm:hover .arr {
  transform: translateX(3px);
}

/* the zooming hero artwork */
.mm-hero-art {
  position: relative;
  z-index: 2;
  width: min(1040px, 94vw);
  aspect-ratio: 16 / 9;
  margin-top: clamp(28px, 5vh, 60px);
  border-radius: 28px 28px 0 0;
  overflow: hidden;
  transform-origin: 50% 100%;
  will-change: transform;
  box-shadow: 0 -10px 60px rgba(28, 30, 24, .10);
}

.mm-hero-art gs-hero-canvas,
.mm-hero-art canvas.hero-canvas {
  position: absolute;
  inset: 0;
}

/* Home hero: let the artwork breathe through the whole opening. The visual
   is intentionally not a card; its objects can drift past the hero edge as
   the next section enters the viewport. */
.hero-home.mm-hero {
  overflow: visible;
  z-index: 2;
}

.hero-home .mm-hero-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  margin: 0;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
  pointer-events: none;
}

.hero-home .mm-hero-art gs-hero-canvas {
  filter: none;
}

.hero-home .mm-hero-art::after {
  display: none;
}

.hero-home .mm-hero-art svg {
  transform: translate3d(var(--scroll-x, 0px), var(--scroll-y, 82px), 0)
    scale(var(--scroll-scale, 1.06));
  transform-origin: 50% 44%;
}

/* soft light wash behind the headline — deliberately faint so the sage
   stays saturated. Was washing the whole hero out at higher alphas. */
.mm-hero::before {
  content: '';
  position: absolute;
  top: -16%;
  left: 50%;
  transform: translateX(-50%);
  width: 56%;
  height: 46%;
  background: radial-gradient(ellipse at 50% 50%, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 64%);
  pointer-events: none;
  z-index: 1;
}

/* the canvas paints pale blobs that read as glare on sage —
   tint it back toward the brand green and knock the brightness down */
.mm-hero-art gs-hero-canvas,
.mm-hero-art canvas.hero-canvas {
  filter: saturate(1.18) brightness(.94);
}

.mm-hero-art::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(179, 226, 156, .30), rgba(179, 226, 156, .08) 55%, rgba(179, 226, 156, 0));
  pointer-events: none;
  z-index: 2;
}

@media (max-width: 700px) {
  .hero.mm-hero {
    padding-top: 132px;
  }
  .hero-home .mm-hero-art {
    height: 92%;
  }
  .mm-hero-art {
    aspect-ratio: 4 / 3;
    border-radius: 20px 20px 0 0;
  }
}

/* ============================================================
   STICKY STACKED CARDS  (Analyze / Create / Elevate)
   ============================================================ */
.mm-stack-section {
  background: var(--mm-cream);
  padding: clamp(90px, 13vh, 150px) 0;
}

.mm-stack-grid {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 clamp(24px, 4vw, 48px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(40px, 5vw, 70px);
}

.mm-stack-intro {
  position: sticky;
  top: 120px;
  align-self: start;
}

.mm-stack-intro h2 {
  font-size: clamp(2.2rem, 4.4vw, 3.7rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.04;
  color: var(--mm-ink);
}

.mm-underline {
  position: relative;
  white-space: nowrap;
}

.mm-underline svg {
  position: absolute;
  left: 0;
  bottom: -.16em;
  width: 100%;
  height: .2em;
  overflow: visible;
}

.mm-underline svg path {
  fill: none;
  stroke: var(--mm-green);
  stroke-width: 7;
  stroke-linecap: round;
}

.mm-stack-intro p {
  margin-top: 28px;
  font-size: 1.02rem;
  line-height: 1.62;
  color: rgba(28, 30, 24, .66);
  max-width: 42ch;
}

.mm-stack-cards {
  position: relative;
}

.mm-card {
  position: sticky;
  top: 120px;
  border-radius: 32px;
  padding: clamp(30px, 3.4vw, 46px);
  min-height: 430px;
  margin-bottom: 34px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  box-shadow: 0 18px 50px rgba(28, 30, 24, .14);
}

.mm-card-step {
  position: absolute;
  top: 26px;
  left: clamp(30px, 3.4vw, 46px);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .14em;
  opacity: .62;
}

.mm-card-icon {
  position: absolute;
  top: 24px;
  right: 24px;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .9);
  display: flex;
  align-items: center;
  justify-content: center;
}

.mm-card-icon svg {
  width: 22px;
  height: 22px;
}

.mm-card h3 {
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  font-weight: 600;
  letter-spacing: -.045em;
  line-height: 1;
  margin: 0;
}

.mm-card p {
  margin-top: 18px;
  font-size: 1rem;
  line-height: 1.55;
  max-width: 40ch;
}

/* card colourways — cream, sage, deep ink */
.mm-card-a { background: #fff; color: var(--mm-ink); }
.mm-card-a p { color: rgba(28, 30, 24, .68); }

.mm-card-b { background: var(--mm-green); color: var(--mm-ink); }
.mm-card-b p { color: rgba(28, 30, 24, .74); }
.mm-card-b .mm-card-icon { background: rgba(255, 255, 255, .92); }

.mm-card-c { background: var(--mm-ink); color: #fff; }
.mm-card-c p { color: rgba(255, 255, 255, .74); }
.mm-card-c .mm-card-icon { background: rgba(255, 255, 255, .14); }

@media (max-width: 900px) {
  .mm-stack-grid {
    grid-template-columns: 1fr;
  }
  .mm-stack-intro {
    position: static;
  }
  .mm-card {
    /* NOT static: .mm-card-step and .mm-card-icon are absolutely positioned
       inside the card. Making the card static removed their containing block,
       so they resolved against a distant ancestor and landed on top of the
       heading. `relative` drops the sticky behaviour without doing that. */
    position: relative;
    min-height: 0;
    padding-top: 68px;      /* clearance for the step label */
    margin-bottom: 18px;
  }

  .mm-card h3 {
    margin-top: 0;
    padding-right: 64px;   /* clear the absolutely positioned icon */
  }
}

/* ============================================================
   STAGGERED REVEALS
   Extends the existing .fi / .fi.vis pattern.
   ============================================================ */
.fi {
  transform: translateY(38px);
  transition: opacity .95s var(--mm-ease), transform .95s var(--mm-ease);
}

.fi[data-mm-delay="1"] { transition-delay: .09s; }
.fi[data-mm-delay="2"] { transition-delay: .18s; }
.fi[data-mm-delay="3"] { transition-delay: .27s; }
.fi[data-mm-delay="4"] { transition-delay: .36s; }

@media (prefers-reduced-motion: reduce) {
  .fi,
  .mm-hero-art,
  .nav-cta,
  .btn-mm {
    transition: none !important;
    transform: none !important;
  }
}

/* ============================================================
   INTRO PARAGRAPH + WINDING PATH CARDS
   Sits between the ACE stack and the services showcase.
   Each card routes to one of the main nav destinations.
   ============================================================ */
.mm-intro {
  background: var(--mm-cream);
  padding: clamp(70px, 10vh, 120px) 0 clamp(50px, 7vh, 90px);
}

.mm-intro-inner {
  max-width: 1240px;
  margin: 0 auto;
  padding: 0 clamp(24px, 4vw, 48px);
}

.mm-intro p {
  font-size: clamp(1.35rem, 2.4vw, 1.95rem);
  font-weight: 500;
  letter-spacing: -.025em;
  line-height: 1.28;
  color: var(--mm-ink);
  max-width: 24ch;
}

.mm-intro .btn-mm {
  margin-top: clamp(28px, 4vh, 46px);
}

/* ── the sage path block ───────────────────────────────── */
.mm-path {
  position: relative;
  background: var(--mm-green);
  border-radius: var(--mm-radius);
  overflow: hidden;
  padding: clamp(70px, 10vh, 120px) 0 clamp(60px, 9vh, 110px);
  margin: 0 clamp(0px, 1.5vw, 20px);
}

.mm-path-line {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

.mm-path-line path {
  fill: none;
  stroke: var(--mm-green-deep);
  stroke-width: 300;
  stroke-linecap: round;
  opacity: .5;
}

.mm-path-deco {
  position: absolute;
  pointer-events: none;
  z-index: 1;
  opacity: .95;
}

.mm-path-card {
  position: relative;
  z-index: 3;
  background: #fff;
  border-radius: 28px;
  padding: clamp(30px, 3.2vw, 44px);
  max-width: 520px;
  margin: clamp(40px, 6vh, 70px) auto;
  box-shadow: 0 16px 50px rgba(28, 30, 24, .13);
}

.mm-path-card:nth-of-type(odd) { margin-left: clamp(24px, 8vw, 140px); }
.mm-path-card:nth-of-type(even) { margin-right: clamp(24px, 8vw, 140px); margin-left: auto; }

.mm-path-card h3 {
  font-size: clamp(1.9rem, 3.6vw, 2.9rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.02;
  color: var(--mm-ink);
  margin: 0 0 16px;
}

.mm-path-card p {
  font-size: 1rem;
  line-height: 1.56;
  color: rgba(28, 30, 24, .68);
  margin: 0 0 26px;
}

.mm-path-card .btn-mm {
  background: var(--mm-cream);
  box-shadow: none;
}

@media (max-width: 860px) {
  .mm-path-card:nth-of-type(odd),
  .mm-path-card:nth-of-type(even) {
    margin-left: 20px;
    margin-right: 20px;
  }
  .mm-path-line path { stroke-width: 460; }
  .mm-path-deco { display: none; }
}

/* ============================================================
   INDUSTRIES WE SERVE  (about.html)
   ============================================================ */
.mm-ind-lede {
  font-size: clamp(1rem, 1.5vw, 1.18rem);
  line-height: 1.55;
  color: rgba(28, 30, 24, .62);
  max-width: 52ch;
  margin: 18px 0 0;
}

.mm-ind-grid {
  position: relative;      /* the origin gs-industries.js measures against */
  margin-top: clamp(26px, 3.2vh, 42px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(16px, 1.8vw, 24px);
}

/* ── the cards themselves ──────────────────────────────────
   .mm-ind-item is the animated wrapper and .mm-ind-card the visible
   surface. Keeping them separate means the entrance transform and the
   hover lift never write to the same property. */
.mm-ind-item {
  position: relative;
  will-change: transform, opacity;
}

/* the resting pose, claimed by gs-industries.js the moment it runs */
.gs-ind-js .mm-ind-item {
  opacity: 0;
  transform: translate3d(0, 90px, 0);
}

/* ── a photograph per card, one green veil across all four ──
   Two layers, and they answer different questions.

   ::before is the card's own photograph — what this industry looks like.
   Each card gets its own, set from --gs-photo below.

   ::after is the SAME green wash on every card, sized to the full grid and
   shifted by each card's own offset within it, so the four are four windows
   onto a single piece of art. That is what stops four unrelated photos from
   reading as four unrelated cards. While a card is still travelling its
   slice is out of register and the seam shows; the wash only resolves once
   the whole row has landed — the artwork completing IS the reveal
   finishing.

   gs-industries.js supplies --gs-art-w/h (the grid's size) and
   --gs-art-x/y (minus the card's offset within it). The fallbacks keep the
   cards presentable if the script never runs. */
.mm-ind-card {
  position: relative;
  height: 100%;
  border-radius: 22px;
  overflow: hidden;
  border: none;
  isolation: isolate;
  background-color: #1B2916;
  transition: box-shadow .45s var(--mm-ease), transform .45s var(--mm-ease);
}

.mm-ind-card::before,
.mm-ind-card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* the photograph */
.mm-ind-card::before {
  z-index: -2;
  background-image: var(--gs-photo);
  background-size: cover;
  background-position: center;
  /* pulled back so four different photographers' colour does not fight the
     veil sitting on top of them */
  filter: grayscale(.24) contrast(1.06) saturate(.9);
}

/* the shared veil, plus a scrim weighted to the foot of the card where the
   copy sits. The scrim is per-card (100% 100%); only the wash is sliced. */
.mm-ind-card::after {
  z-index: -1;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(180deg,
      rgba(8, 20, 6, .40) 0%,
      rgba(8, 20, 6, .06) 26%,
      rgba(8, 20, 6, 0) 38%,
      rgba(8, 20, 6, .52) 70%,
      rgba(6, 16, 5, .86) 100%),
    radial-gradient(ellipse 46% 118% at 14% 24%, rgba(184, 226, 156, .30), rgba(184, 226, 156, 0) 64%),
    radial-gradient(ellipse 54% 126% at 84% 14%, rgba(12, 38, 8, .34), rgba(12, 38, 8, 0) 66%),
    linear-gradient(112deg, rgba(78, 138, 54, .48) 0%, rgba(52, 106, 38, .54) 44%, rgba(28, 68, 22, .60) 100%);
  background-size:
    100% 100%,
    var(--gs-art-w, 100%) var(--gs-art-h, 100%),
    var(--gs-art-w, 100%) var(--gs-art-h, 100%),
    var(--gs-art-w, 100%) var(--gs-art-h, 100%);
  background-position:
    0 0,
    var(--gs-art-x, 0px) var(--gs-art-y, 0px),
    var(--gs-art-x, 0px) var(--gs-art-y, 0px),
    var(--gs-art-x, 0px) var(--gs-art-y, 0px);
}

/* which photograph goes on which card */
.mm-ind-item:nth-child(1) .mm-ind-card {
  --gs-photo: image-set(url('../img/industries/realestate.webp') type('image/webp'),
                        url('../img/industries/realestate.jpg') type('image/jpeg'));
}
.mm-ind-item:nth-child(2) .mm-ind-card {
  --gs-photo: image-set(url('../img/industries/retail.webp') type('image/webp'),
                        url('../img/industries/retail.jpg') type('image/jpeg'));
}
.mm-ind-item:nth-child(3) .mm-ind-card {
  --gs-photo: image-set(url('../img/industries/agencies.webp') type('image/webp'),
                        url('../img/industries/agencies.jpg') type('image/jpeg'));
}
.mm-ind-item:nth-child(4) .mm-ind-card {
  --gs-photo: image-set(url('../img/industries/consultancies.webp') type('image/webp'),
                        url('../img/industries/consultancies.jpg') type('image/jpeg'));
}

/* ── copy, re-weighted for a photographic surface ────────── */
.mm-ind-card h3 { color: #fff; }

.mm-ind-card > p {
  color: rgba(255, 255, 255, .84);
}

.mm-ind-card .gs-ref {
  color: #fff;
  text-decoration-color: rgba(255, 255, 255, .55);
}

.mm-ind-card .gs-ref:hover {
  text-decoration-color: #fff;
}

/* the chip becomes frosted glass rather than a white tile */
.mm-ind-card .ptc-icon {
  background: rgba(255, 255, 255, .15);
  border: 1px solid rgba(255, 255, 255, .26);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.mm-ind-card .ptc-icon svg { stroke: #fff; }

.mm-ind-item:hover .mm-ind-card {
  transform: translateY(-6px);
  box-shadow: 0 22px 50px rgba(14, 30, 10, .34);
}

/* the photograph drifts in a touch on hover — the card is a window */
.mm-ind-item:hover .mm-ind-card::before {
  transform: scale(1.04);
}

.mm-ind-card::before {
  transition: transform .7s var(--mm-ease);
}

/* headline gets a sage rule that draws across on hover */
.mm-ind-card .ptc-top h3 {
  position: relative;
  display: inline-block;
}

.mm-ind-card .ptc-top h3::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -5px;
  height: 2px;
  width: 0;
  background: var(--mm-green);
  transition: width .5s var(--mm-ease);
}

.mm-ind-card:hover .ptc-top h3::after { width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .mm-ind-item,
  .mm-ind-card {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ============================================================
   HOME HERO — full-bleed floating scene
   No card, no border. Objects sit on the sage field and are
   free to travel past the hero into the cream section below.
   ============================================================ */
/* NOTE the doubled class. `.hero.mm-hero { padding: ... }` is specificity
   (0,2,0); a single-class `.mm-hero--scene { padding-top }` at (0,1,0) lost
   to it, so the art-directed position silently never applied. */
.hero.mm-hero--scene {
  overflow: visible;          /* let objects bleed into the next section */
  z-index: 2;                 /* ...and paint above it */
  justify-content: flex-start;/* headline rides high, art fills below */
  padding-top: clamp(118px, 30.6vh, 400px);   /* 398/1300 of the reference */
  padding-bottom: clamp(90px, 14vh, 160px);
}

/* the section beneath must sit under the overhanging objects */
.mm-hero--scene + section,
.mm-hero--scene + div,
.mm-stack-section { position: relative; z-index: 1; }

/* the sage block still needs its rounded corners clipped, so the
   background lives on a pseudo-element rather than the section box */
.mm-hero--scene {
  background: transparent;
}

.mm-hero--scene::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--mm-green);
  border-radius: 0 0 var(--mm-radius) var(--mm-radius);
  z-index: 0;
}

.mm-hero--scene .hero-content { z-index: 4; }

/* ── photo heroes: a real image instead of the flat sage field ──
   A dark gradient sits under the photo so the (otherwise dark-ink)
   headline stays legible without needing a separate light-text variant.
   Each page supplies its own image via the page-specific class. */
.hero-partner.mm-hero--scene::after {
  background:
    linear-gradient(180deg, rgba(20, 24, 18, .58) 0%, rgba(20, 24, 18, .30) 42%, rgba(20, 24, 18, .12) 68%, rgba(20, 24, 18, .38) 100%),
    url('../../images/partner-hero.jpg') center 30% / cover no-repeat;
}

.hero-about.mm-hero--scene::after {
  background:
    linear-gradient(180deg, rgba(20, 24, 18, .58) 0%, rgba(20, 24, 18, .30) 42%, rgba(20, 24, 18, .12) 68%, rgba(20, 24, 18, .38) 100%),
    url('../../images/about-hero.jpg') center 30% / cover no-repeat;
}

.hero-work.mm-hero--scene::after {
  background:
    linear-gradient(180deg, rgba(20, 24, 18, .58) 0%, rgba(20, 24, 18, .30) 42%, rgba(20, 24, 18, .12) 68%, rgba(20, 24, 18, .38) 100%),
    url('../img/work/work-hero.jpg') center 30% / cover no-repeat;
}

.hero-partner.mm-hero--scene .hero-title,
.hero-about.mm-hero--scene .hero-title,
.hero-work.mm-hero--scene .hero-title {
  color: #fff;
  text-shadow: 0 4px 28px rgba(0, 0, 0, .35);
}

/* ── scene canvas ─────────────────────────────────────────── */
gs-hero-scene {
  position: absolute;
  inset: 0;
  display: block;
  z-index: 2;                 /* above the sage, below the headline */
  pointer-events: none;
  /* `paint` containment would clip the objects that are meant to
     overhang into the cream section — layout containment only. */
  contain: layout;
}

.gs-scene {
  position: absolute;
  inset: 0;
  transform: translate3d(0, var(--sy, 0px), 0) scale(var(--ss, 1));
  transform-origin: 50% 40%;
  will-change: transform;
}

/* ── one object ───────────────────────────────────────────── */
.gs-obj {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--size);
  /* centred on its own x/y regardless of the art's aspect ratio,
     then displaced by depth: nearer objects travel further on scroll */
  transform:
    translate(-50%, -50%)
    translate3d(calc(var(--sx, 0px) * var(--depth)),
                calc(var(--sy, 0px) * var(--depth) * .55), 0)
    rotate(var(--rot));
  will-change: transform;
}

/* resting state is declared here (not inline) so `.is-settled` can win */
.gs-obj-enter {
  transform: translate3d(var(--ex, 0), var(--ey, 0), 0) scale(.72);
  opacity: 0;
  transition-property: transform, opacity;
  transition-timing-function: cubic-bezier(.16, 1, .3, 1);
  transition-duration: 1700ms;
  will-change: transform, opacity;
}

.is-settled .gs-obj-enter {
  transform: translate3d(0, 0, 0) scale(1);
  opacity: 1;
}

.gs-obj-amb { display: block; }
.gs-obj-amb svg { display: block; width: 100%; height: auto; overflow: visible; }

/* ── ambient loops — GPU only, no JS ──────────────────────── */
.gs-amb-float,
.gs-amb-drift,
.gs-amb-spin,
.gs-amb-pulse,
.gs-amb-orbit {
  animation-iteration-count: infinite;
  animation-timing-function: ease-in-out;
}

.gs-amb-float { animation-name: gsFloat; }
.gs-amb-drift { animation-name: gsDrift; }
.gs-amb-pulse { animation-name: gsPulse; }
.gs-amb-orbit { animation-name: gsOrbit; }
.gs-amb-spin  { animation-name: gsSpin; animation-timing-function: linear; }

@keyframes gsFloat {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(0, -14px, 0) rotate(1.6deg); }
}

@keyframes gsDrift {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  33%      { transform: translate3d(10px, -8px, 0) rotate(-1.2deg); }
  66%      { transform: translate3d(-8px, -14px, 0) rotate(1deg); }
}

@keyframes gsSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes gsPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.07); }
}

@keyframes gsOrbit {
  0%   { transform: translate3d(0, 0, 0); }
  25%  { transform: translate3d(16px, -12px, 0); }
  50%  { transform: translate3d(0, -24px, 0); }
  75%  { transform: translate3d(-16px, -12px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}

/* ── connector signals ────────────────────────────────────── */
.gs-links {
  position: absolute;
  inset: 0;
  opacity: var(--slink, 1);
}

.gs-links svg { width: 100%; height: 100%; display: block; }

.gs-links path {
  fill: none;
  stroke: var(--mm-ink);
  stroke-width: 1.6;
  opacity: .16;
  stroke-linecap: round;
  stroke-dasharray: 3 260;
  animation: gsSignal 9s linear infinite;
}

@keyframes gsSignal {
  from { stroke-dashoffset: 263; }
  to   { stroke-dashoffset: 0; }
}

/* ── responsive ───────────────────────────────────────────── */
@media (max-width: 820px) {
  .gs-obj--lg { display: none; }
  .hero.mm-hero--scene { padding-bottom: clamp(70px, 12vh, 120px); }
}

/* ── reduced motion: a composed still, not a dead page ────── */
@media (prefers-reduced-motion: reduce) {
  .gs-obj-amb,
  .gs-links path {
    animation: none !important;
  }
  .gs-obj-enter {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
  .gs-scene { transform: none !important; }
}

/* ============================================================
   UNIFORM MOTION LAYER
   One easing curve, one rise distance, one hover behaviour for
   every card-like component on every page. Anything that already
   had bespoke motion is normalised here.
   ============================================================ */
:root {
  --mm-rise: 38px;      /* how far reveals travel */
  --mm-dur: .95s;       /* reveal duration */
  --mm-hover: -6px;     /* hover lift */
  --mm-hover-dur: .45s;
}

/* every reveal shares the same curve and distance */
.fi {
  opacity: 0;
  transform: translateY(var(--mm-rise));
  transition: opacity var(--mm-dur) var(--mm-ease),
              transform var(--mm-dur) var(--mm-ease);
}

.fi.vis { opacity: 1; transform: none; }

/* ── shared hover for every card surface ────────────────── */
.testi,
.bento-card,
.wk-item,
.partner-benefit-card,
.pstep,
.tw-item,
.mm-path-card,
.article-card,
.partner-split-image {
  transition: transform var(--mm-hover-dur) var(--mm-ease),
              box-shadow var(--mm-hover-dur) var(--mm-ease);
  will-change: transform;
}

.testi:hover,
.bento-card:hover,
.wk-item:hover,
.partner-benefit-card:hover,
.pstep:hover,
.tw-item:hover,
.mm-path-card:hover,
.article-card:hover {
  transform: translateY(var(--mm-hover));
  box-shadow: 0 20px 46px rgba(28, 30, 24, .13);
}

/* media inside a card breathes on hover, uniformly */
.wk-item img,
.partner-split-image img,
.article-card img,
.mm-stack-cards img {
  transition: transform 1.1s var(--mm-ease);
  will-change: transform;
}

.wk-item:hover img,
.partner-split-image:hover img,
.article-card:hover img { transform: scale(1.045); }

/* ── section headings rise as one unit ──────────────────── */
.sec-label.fi { --mm-rise: 22px; }

/* ── numbered / stepped lists cascade ───────────────────── */
.pstep.fi:nth-of-type(1),
.tw-item.fi:nth-of-type(1) { transition-delay: 0s; }
.pstep.fi:nth-of-type(2),
.tw-item.fi:nth-of-type(2) { transition-delay: .09s; }
.pstep.fi:nth-of-type(3),
.tw-item.fi:nth-of-type(3) { transition-delay: .18s; }
.pstep.fi:nth-of-type(4),
.tw-item.fi:nth-of-type(4) { transition-delay: .27s; }

/* ── every arrow-bearing control behaves the same ───────── */
.btn-dark .arr,
.btn-mm .arr,
.cs-pill-arr,
.wk-arrow {
  transition: transform .35s var(--mm-ease);
}

.btn-dark:hover .arr,
.btn-mm:hover .arr,
.wk-item:hover .wk-arrow,
.cs-pill:hover .cs-pill-arr { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .fi,
  .testi, .bento-card, .wk-item, .partner-benefit-card,
  .pstep, .tw-item, .mm-path-card, .article-card {
    transition: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
}

/* ── Industries: pinned stage ──────────────────────────────
   The heading, the rule and the row are held still while the reader
   keeps scrolling, and that scroll is what pulls each card up. Without
   the pin the whole row would resolve in the moment the section entered
   the viewport; with it, the four cards are four distinct beats and the
   reader has to keep going to earn them.

   Scrolling itself is never intercepted — the section is skippable, it
   just has more runway than it has height. */
.mm-ind-stage {
  position: relative;
  height: 260vh;                /* scroll distance the reveal consumes */
}

/* Exactly one viewport tall, never more: the row is the flexible part, so
   whatever the heading does not use is what the cards get. Sizing the cards
   directly instead would overflow the pin the moment the copy wrapped to
   another line. The heading is kept tight for the same reason — every pixel
   it gives back becomes card. */
.mm-ind-sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--mm-nav-h) + 14px) 0 clamp(20px, 2.6vh, 34px);
}

/* The section h2 carries a 64px bottom margin meant for a heading that ends
   a block. Here it is followed immediately by its own lede — and inside the
   pin that margin is 64px taken straight off the height of the cards. */
.mm-ind-section h2 {
  margin-bottom: 0;
}

.mm-ind-section .mm-ind-lede {
  margin-top: 12px;
}

.mm-ind-sticky > .mm-ind-grid {
  flex: 1 1 auto;
  min-height: 0;
  max-height: 780px;
}

/* ── Industries: four cards, full width ────────────────────
   The row is locked to four equal columns and given the whole
   viewport width to breathe in. */
.mm-ind-section {
  padding-left: clamp(24px, 3vw, 44px);
  padding-right: clamp(24px, 3vw, 44px);
  padding-bottom: 0;
}

.mm-ind-grid {
  max-width: none;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(16px, 1.6vw, 26px);
}

/* Inside the pin the row is stretched to the space left over, so the card
   takes its height from the grid rather than asking for one. The
   min-height only matters once the stage collapses and the cards stack. */
.mm-ind-card {
  padding: clamp(30px, 2.6vw, 46px) clamp(22px, 2vw, 34px);
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.mm-ind-card .ptc-top { margin-bottom: clamp(14px, 1.6vw, 24px); }

.mm-ind-card .ptc-top h3 {
  font-size: clamp(1.12rem, 1.5vw, 1.6rem);
  letter-spacing: -.025em;
  line-height: 1.15;
}

.mm-ind-card > p {
  margin-top: auto;                 /* copy sits to the baseline */
  font-size: clamp(.92rem, 1vw, 1.06rem);
  line-height: 1.58;
}

/* Two things retire the pin. Below the four-column layout the cards are
   stacked, so holding the reader still would only make them scroll a long
   way to watch a list appear. And on a short viewport the heading, rule
   and row simply do not fit one screen, so pinning would crop the cards.
   In both cases the stage collapses and each card reveals on its own
   approach. gs-industries.js reads the sticky element's computed position
   rather than duplicating these conditions. */
@media (max-width: 1080px), (max-height: 700px) {
  .mm-ind-stage { height: auto; }
  .mm-ind-sticky {
    position: static;
    height: auto;
    padding: 0;
  }
  .mm-ind-sticky > .mm-ind-grid {
    flex: none;
    max-height: none;
  }
  /* out of the pin the cards size themselves, and they keep the tall
     portrait proportion rather than collapsing to fit their text */
  .mm-ind-card { min-height: min(560px, 66vh); }
  .mm-ind-section { padding-bottom: clamp(64px, 9vh, 110px); }
}

@media (max-width: 1080px) {
  .mm-ind-grid { grid-template-columns: repeat(2, 1fr); }
}

/* One card per screen, near enough: the heading sits at the top, the
   photograph carries the middle, and the copy is pushed to the foot by
   `margin-top: auto`. Filling the viewport is what makes the photograph
   worth having — a short card is just a tinted strip. */
@media (max-width: 620px) {
  .mm-ind-grid {
    grid-template-columns: 1fr;
    gap: clamp(14px, 3vw, 20px);
  }
  .mm-ind-card {
    min-height: 68svh;
    padding: clamp(26px, 6vw, 34px) clamp(22px, 5.5vw, 30px) clamp(28px, 6vw, 36px);
  }

  /* The desktop size is set against a 378px column. Given the full width of
     a phone the same value reads as a caption, not a title. */
  .mm-ind-card .ptc-top h3 {
    font-size: clamp(1.5rem, 6.4vw, 1.95rem);
    line-height: 1.1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mm-ind-stage { height: auto; }
  .mm-ind-sticky { position: static; height: auto; padding: 0; }
  .mm-ind-sticky > .mm-ind-grid { flex: none; max-height: none; }
  .mm-ind-card { min-height: min(560px, 66vh); }
}

/* ── hero headline: un-clip the reveal mask ────────────────
   main.js wraps every word in .split-parent { overflow:hidden } so the
   GSAP reveal can slide each word up behind a mask. That mask clips at
   the baseline, which lops the tail off every g, p, y and j. Extending
   the padding box downward puts descenders inside the mask, and the
   matching negative margin keeps the line spacing unchanged.
   The box's shrink-to-fit width is likewise based on advance metrics,
   not ink extent — at this title's -.055em tracking the last glyph in
   a word (w, p, s, y…) routinely paints past its own advance box, so
   the same word gets its trailing edge sheared off too. Pad the right
   side the same way to give that overflow room before the mask clips it. */
.mm-hero .hero-title .split-parent {
  overflow: hidden;
  padding-bottom: .2em;
  margin-bottom: -.2em;
  padding-right: .12em;
  margin-right: -.12em;
  vertical-align: bottom;
}

/* the word spans are inline-blocks; keep the gaps between them even */
.mm-hero .hero-title .split-child {
  will-change: transform;
}

/* ── mobile quote route ────────────────────────────────────
   Contact is no longer a nav item and .nav-cta is hidden under
   1180px, so mm-hero.js mirrors the quote link into the list.
   It is only needed where the pill is not shown. */
.nav-item--cta { display: none; }

@media (max-width: 1180px) {
  .nav-item--cta { display: block; }
}

/* ============================================================
   MOBILE REFINEMENT
   Findings from a real 414x896 render, not guesswork:
     - 64 :hover rules, none guarded, all latch after a tap
     - 9 tap targets under the 44px minimum
     - the industries deck rendered back-side-out in one column
   ============================================================ */

/* ── touch: hover states must not latch ────────────────────
   A tap leaves :hover applied until you tap elsewhere, so cards
   stay lifted and shadowed. Neutralise them where there is no
   real pointer, and give a genuine press state instead. */
@media (hover: none) {
  .testi:hover,
  .bento-card:hover,
  .wk-item:hover,
  .partner-benefit-card:hover,
  .pstep:hover,
  .tw-item:hover,
  .mm-path-card:hover,
  .article-card:hover,
  .mm-ind-item:hover .mm-ind-card,
  .btn-dark:hover,
  .btn-mm:hover,
  .nav-cta:hover,
  .mm-hero .btn-dark:hover {
    transform: none;
    box-shadow: inherit;
  }

  .wk-item:hover img,
  .partner-split-image:hover img,
  .article-card:hover img { transform: none; }

  .nav-cta:hover .nav-cta-badge,
  .mm-ind-item:hover .ptc-icon { transform: none; }

  .mm-ind-item:hover .ptc-top h3::after,
  .mm-ind-card:hover .ptc-top h3::after { width: 0; }

  /* press feedback, which touch actually needs */
  a:active,
  button:active,
  .btn-dark:active,
  .btn-mm:active,
  .nav-cta:active,
  .mm-ind-card:active,
  .bento-card:active,
  .wk-item:active,
  .mm-path-card:active {
    transform: scale(.978);
    transition: transform .09s ease-out;
  }
}

html { -webkit-tap-highlight-color: rgba(28, 30, 24, .06); }

/* ── tap targets: 44px minimum ─────────────────────────────
   Measured under: nav links 43px, footer links 20px. */
@media (max-width: 768px) {
  body > nav .nav-item > a {
    min-height: 48px;
    padding: 13px 18px;
    font-size: 1.06rem;
  }

  body > nav .nav-center {
    padding: 10px 12px;
    gap: 2px;
  }

  .nav-mobile-toggle {
    min-width: 48px;
    min-height: 48px;
  }

  /* footer and inline links were 20-22px tall */
  site-footer a,
  .ft-links a,
  .ft-col a,
  .foot-links a,
  .cs-pill,
  .sec-label + a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .btn-dark,
  .btn-mm,
  .cta-btns a {
    min-height: 48px;
    padding-top: 12px;
    padding-bottom: 12px;
  }
}

/* ── hero scene: lighter on phones ─────────────────────────
   The objects are decorative; on a small screen they crowd the
   headline and cost paint. Trim the set and calm the motion. */
@media (max-width: 620px) {
  .gs-obj--lg { display: none; }
  .gs-links { display: none; }          /* hairline connectors read as noise */
  .gs-scene { opacity: .92; }
}

/* ── mobile hero: match the reference proportions ──────────
   Measured against mindmarket.com on a 440px phone: the headline
   fills roughly 80% of the width and the block starts about a
   third of the way down. Ours was 38px starting at 190px, which
   read as a caption rather than a headline. */
@media (max-width: 700px) {
  .mm-hero .hero-title {
    font-size: clamp(2.9rem, 15.5vw, 4.6rem);
    letter-spacing: -.045em;
    line-height: 1.0;
    max-width: 12ch;
  }

  .mm-hero-sub {
    margin-top: 22px;
    font-size: 1.05rem;
  }

  .hero.mm-hero--scene {
    padding-top: clamp(150px, 32vh, 320px);
    padding-bottom: clamp(60px, 10vh, 110px);
  }

  .mm-hero .hero-btns { margin-top: 26px; }
}

/* iOS: stop the hero locking to a stale 100vh when the URL bar hides */
@supports (height: 100svh) {
  @media (max-width: 768px) {
    .hero.mm-hero { min-height: 70svh; }
  }
}

/* the last tap targets under 44px: contact email link and footer social icons */
@media (max-width: 768px) {
  .cbox-intro a[href^="mailto"],
  a[href^="mailto"] {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .footer-socials .fsoc,
  .fsoc {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* heading added above the positioning paragraph in the intro block */
.mm-intro-h {
  font-size: clamp(1.9rem, 3.6vw, 3rem);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.05;
  color: var(--mm-ink);
  max-width: 18ch;
  margin: 0 0 clamp(18px, 2.4vw, 30px);
}

/* ── mobile compositing budget ─────────────────────────────
   Every .gs-obj carried `will-change: transform`, which promotes each
   one to its own layer. Ten layers plus the scene wrapper is a lot for
   a phone GPU and shows up as scroll stutter. The parallax still runs;
   it just stops asking for a dedicated layer per object. */
@media (max-width: 768px) {
  .gs-obj,
  .gs-obj-enter,
  .gs-scene {
    will-change: auto;
  }

  .mm-ind-item {
    will-change: auto;
  }

  .gs-photo-bg,
  .gs-panel--photo .gs-panel-bg {
    will-change: auto;
  }

  /* the blurred radial wash is expensive to repaint while scrolling */
  .mm-hero::before { filter: none; }
}

/* ============================================================
   RIBBON SECTION
   A tall section provides the scroll distance; a sticky stage holds
   the copy still while two lines fall from under the header, cut down
   through the section, and resolve into the GS mark directly beneath
   the paragraph. Choreographed by gs-ribbon.js.

   The runway is deliberately short. The mark lands near the end of it,
   so the work list arrives immediately after the logo rather than
   after a screen of empty cream.
   ============================================================ */
.gs-ribbon {
  position: relative;
  height: 200vh;                 /* the scroll runway */
  background: var(--mm-cream);
}

.gs-ribbon-stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
}

/* The SVG spans the whole stage. gs-ribbon.js rebuilds its viewBox to the
   stage's own aspect on every layout, so one view unit is the same distance
   on both axes and nothing is cropped — which is what lets the script place
   the mark from the copy block's measured position. */
.gs-ribbon-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* The copy holds its place for the whole sequence. The mark forms below it,
   so it must not travel or fade — the two are read together. */
.gs-ribbon-copy {
  position: absolute;
  z-index: 1;
  top: clamp(88px, 13vh, 150px);
  left: clamp(24px, 4vw, 60px);
  right: clamp(24px, 4vw, 60px);
  pointer-events: none;
}

.gs-ribbon-copy h2 {
  font-size: clamp(2.4rem, 5.4vw, 5.6rem);
  font-weight: 500;
  letter-spacing: -.055em;
  line-height: .97;
  color: var(--mm-ink);
  max-width: 13ch;
  margin: 18px 0 0;
  text-wrap: balance;
}

.gs-ribbon-lede {
  margin: clamp(20px, 2.6vh, 34px) 0 0;
  font-size: clamp(1rem, 1.35vw, 1.16rem);
  line-height: 1.6;
  color: rgba(28, 30, 24, .68);
  max-width: 42ch;
}

/* The list of work follows the mark directly. The section's usual 110px lid
   would reintroduce the gap the sticky stage was just tightened to remove. */
.gs-ribbon + .section { padding-top: clamp(28px, 4vh, 52px); }

@media (max-width: 768px) {
  /* The stage keeps the full viewport on phones too: the lines need the
     height to read as a fall, and the mark needs room under the paragraph. */
  .gs-ribbon { height: 190vh; }
  .gs-ribbon-stage { height: 100svh; }
  .gs-ribbon-copy { top: clamp(80px, 11vh, 130px); left: 20px; right: 20px; }
  .gs-ribbon-copy h2 { font-size: clamp(2.1rem, 9.4vw, 3rem); max-width: 11ch; }
  .gs-ribbon-lede { font-size: .96rem; max-width: 34ch; }
}

@media (prefers-reduced-motion: reduce) {
  .gs-ribbon { height: auto; }
  .gs-ribbon-stage { position: relative; height: 92svh; }
}

/* ============================================================
   HOMEPAGE SERVICE CARDS AS LINKS
   The cards became <a> elements so the whole card is the target.
   GSAP drives them by class, so the stacking is untouched.
   ============================================================ */
a.sc-card {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* transform is owned by GSAP, so the hover affordance has to live on
   shadow and the cue rather than on a lift */
a.sc-card {
  transition: box-shadow .45s var(--mm-ease);
}

a.sc-card:hover {
  box-shadow: 0 34px 80px -22px rgba(28, 30, 24, .22);
}

a.sc-card:focus-visible {
  outline: 3px solid var(--mm-ink);
  outline-offset: 4px;
}

.sc-go {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  font-size: .93rem;
  font-weight: 500;
  letter-spacing: -.01em;
  color: var(--mm-ink);
  opacity: .72;
  transition: opacity .35s var(--mm-ease), gap .35s var(--mm-ease);
}

.sc-go i {
  font-style: normal;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(28, 30, 24, .08);
  font-size: 1.05rem;
  line-height: 1;
  transform: translateY(-1px);
}

a.sc-card:hover .sc-go { opacity: 1; gap: 16px; }

/* Touch devices keep hover states stuck on after a tap, so neutralise
   them and give the cue its resting appearance instead. */
@media (hover: none) {
  a.sc-card:hover { box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .10); }
  a.sc-card:hover .sc-go { opacity: .72; gap: 10px; }
}

/* ============================================================
   SERVICE PAGE: PROCESS FLOW
   Four steps zig-zagging either side of an isometric diagram.
   The diagram is one <gs-flow> element; the words are plain HTML.
   ============================================================ */
.gs-proc {
  background: var(--mm-cream);
  padding-block: clamp(72px, 11vh, 140px);
}

.gs-proc-head {
  max-width: 1400px;
  margin: 0 auto clamp(28px, 5vh, 64px);
  padding-inline: 60px;
}

.gs-proc-head h2 {
  font-size: clamp(2.1rem, 5.2vw, 4rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1;
  margin: 14px 0 0;
  max-width: 18ch;
  color: var(--mm-ink);
}

.gs-proc-lede {
  margin: 20px 0 0;
  max-width: 54ch;
  font-size: clamp(1rem, 1.25vw, 1.12rem);
  line-height: 1.65;
  color: rgba(28, 30, 24, .68);
}

.gs-proc-grid {
  max-width: 1400px;
  margin: 0 auto;
  padding-inline: 60px;
  display: grid;
  grid-template-columns: 1fr minmax(280px, 42%) 1fr;
  column-gap: clamp(18px, 3vw, 46px);
  row-gap: clamp(30px, 5vh, 70px);
  align-items: center;
}

/* The diagram spans all four step rows and stays put while the steps
   scroll past it, which is what ties a step to the stop it describes. */
.gs-proc-grid gs-flow {
  grid-column: 2;
  grid-row: 1 / span 4;
  position: sticky;
  top: 18vh;
  display: block;
  align-self: center;
}

.gs-proc-grid gs-flow svg { width: 100%; height: auto; display: block; }

.gs-proc-step { max-width: 42ch; }
.gs-proc-step:nth-of-type(1) { grid-column: 1; grid-row: 1; }
.gs-proc-step:nth-of-type(2) { grid-column: 3; grid-row: 2; }
.gs-proc-step:nth-of-type(3) { grid-column: 1; grid-row: 3; }
.gs-proc-step:nth-of-type(4) { grid-column: 3; grid-row: 4; }

.gs-proc-n {
  display: block;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(28, 30, 24, .42);
}

.gs-proc-step h3 {
  font-size: clamp(1.4rem, 2.5vw, 2rem);
  font-weight: 500;
  letter-spacing: -.035em;
  line-height: 1.08;
  margin: 10px 0 0;
  color: var(--mm-ink);
}

.gs-proc-step p {
  margin: 12px 0 0;
  font-size: 1rem;
  line-height: 1.62;
  color: rgba(28, 30, 24, .70);
}

/* the worked example, set apart so it does not read as more description */
.gs-proc-eg {
  margin-top: 14px !important;
  padding-left: 16px;
  border-left: 2px solid var(--mm-green);
  font-size: .93rem !important;
  color: rgba(28, 30, 24, .58) !important;
}

.gs-proc-eg strong { font-weight: 600; color: rgba(28, 30, 24, .78); }

@media (max-width: 900px) {
  .gs-proc-grid {
    grid-template-columns: 1fr;
    row-gap: clamp(26px, 4vh, 40px);
  }
  /* Explicit placement has to be unset, or the steps stay pinned to the
     columns and rows they were given at the wider breakpoint. */
  .gs-proc-grid gs-flow,
  .gs-proc-step:nth-of-type(1),
  .gs-proc-step:nth-of-type(2),
  .gs-proc-step:nth-of-type(3),
  .gs-proc-step:nth-of-type(4) {
    grid-column: 1;
    grid-row: auto;
  }
  .gs-proc-grid gs-flow { position: static; margin-bottom: 8px; }
  .gs-proc-step { max-width: none; }
}

/* ============================================================
   SERVICE PAGE: CAPABILITY TILES
   Monoline icons, one weight, so the grid reads as a single set.
   ============================================================ */
.gs-caps {
  padding-block: clamp(72px, 11vh, 130px);
}

.gs-caps-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding-inline: 60px;
}

.gs-caps-inner h2 {
  font-size: clamp(1.9rem, 4.4vw, 3.2rem);
  font-weight: 500;
  letter-spacing: -.045em;
  line-height: 1.04;
  margin: 14px 0 clamp(32px, 5vh, 60px);
  max-width: 20ch;
  color: var(--mm-ink);
}

.gs-caps-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  gap: 1px;
  background: rgba(28, 30, 24, .10);
  border: 1px solid rgba(28, 30, 24, .10);
  border-radius: 22px;
  overflow: hidden;
}

/* 1px gaps over a tinted background draw the rules, so no cell needs a
   border of its own and no rule doubles up at a seam. */
.gs-cap {
  background: var(--mm-cream);
  padding: clamp(24px, 3vw, 38px);
}

.gs-cap i {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  background: rgba(179, 226, 156, .34);
  color: var(--mm-ink);
}

.gs-cap gs-icon { display: block; width: 24px; height: 24px; }
.gs-cap gs-icon svg { width: 100%; height: 100%; display: block; }

.gs-cap h3 {
  font-size: 1.12rem;
  font-weight: 600;
  letter-spacing: -.02em;
  margin: 18px 0 0;
  color: var(--mm-ink);
}

.gs-cap p {
  margin: 9px 0 0;
  font-size: .96rem;
  line-height: 1.58;
  color: rgba(28, 30, 24, .66);
}

@media (prefers-reduced-motion: reduce) {
  .gs-proc-grid gs-flow { position: static; }
}

/* ============================================================
   SERVICE PAGE LAYOUT B: SPLIT EDITORIAL LIST
   Statement on the left, a ruled stack of headings on the right.
   Used where the content is a set of problems rather than features.
   ============================================================ */
.gs-split { padding-block: clamp(72px, 11vh, 130px); }

.gs-split-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding-inline: 60px;
  display: grid;
  grid-template-columns: minmax(0, .86fr) minmax(0, 1.35fr);
  gap: clamp(30px, 5vw, 90px);
}

.gs-split-head h2 {
  font-size: clamp(2.1rem, 5vw, 3.9rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1;
  margin: 14px 0 0;
  color: var(--mm-ink);
}

.gs-split-head h2 span { color: rgba(28, 30, 24, .40); }

.gs-split-head p {
  margin: 24px 0 0;
  font-size: clamp(1rem, 1.25vw, 1.1rem);
  line-height: 1.62;
  color: rgba(28, 30, 24, .68);
  max-width: 40ch;
}

.gs-split-item {
  padding: clamp(22px, 3vh, 34px) 0;
  border-top: 1px solid rgba(28, 30, 24, .13);
}

.gs-split-item:first-child { border-top: 0; padding-top: 0; }
.gs-split-item:last-child { padding-bottom: 0; }

.gs-split-item h3 {
  font-size: clamp(1.35rem, 2.9vw, 2.15rem);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1.06;
  margin: 0;
  color: var(--mm-ink);
}

.gs-split-item p {
  margin: 12px 0 0;
  font-size: 1rem;
  line-height: 1.6;
  color: rgba(28, 30, 24, .64);
  max-width: 58ch;
}

@media (max-width: 900px) {
  .gs-split-inner { grid-template-columns: 1fr; gap: clamp(28px, 5vh, 48px); }
}

/* ============================================================
   SERVICE PAGE LAYOUT C: PHOTOGRAPH CARD WITH GLASS TILES
   A full-bleed image inside a rounded card, heading over it, and
   translucent tiles along the bottom.

   The gradient on .gs-photo-card is not decoration: it is what the
   card falls back to if the photograph is missing, so the section
   always looks finished rather than broken.
   ============================================================ */
.gs-photo { padding-block: clamp(48px, 8vh, 100px); }

.gs-photo-card {
  position: relative;
  max-width: 1400px;
  margin: 0 auto;
  border-radius: clamp(20px, 2.4vw, 34px);
  overflow: hidden;
  isolation: isolate;
  min-height: clamp(520px, 72vh, 780px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(32px, 5vw, 66px);
  background: linear-gradient(150deg, #2C3A24 0%, #43552F 44%, #6D8A4C 100%);
}

.gs-photo-bg {
  position: absolute;
  /* Taller than the card so there is travel for the scroll pan.
     20% extra on each side matches the JS travel; the image never
     uncovers the card. */
  inset: -20% 0;
  z-index: -2;
  display: block;
  will-change: transform;
}

.gs-photo-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Keeps the heading legible whatever the photograph turns out to be. */
.gs-photo-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(18, 22, 14, .62) 0%, rgba(18, 22, 14, .28) 38%,
                    rgba(18, 22, 14, .70) 100%);
}

.gs-photo-label {
  display: block;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .78);
}

.gs-photo-head h2 {
  font-size: clamp(2.1rem, 5.6vw, 4.4rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1;
  margin: 16px 0 0;
  max-width: 16ch;
  color: #fff;
}

.gs-photo-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(10px, 1.2vw, 18px);
  margin-top: clamp(40px, 8vh, 90px);
}

.gs-photo-tile {
  padding: clamp(18px, 2vw, 26px);
  border-radius: 16px;
  background: rgba(20, 24, 16, .40);
  border: 1px solid rgba(255, 255, 255, .14);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

.gs-photo-tile h3 {
  font-size: clamp(1.02rem, 1.5vw, 1.24rem);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.16;
  margin: 0;
  color: #fff;
}

.gs-photo-tile p {
  margin: 12px 0 0;
  font-size: .93rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, .78);
}

/* Variant: heading on the left, tiles stacked down the right. */
.gs-photo--side .gs-photo-card {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  align-items: center;
  gap: clamp(28px, 4vw, 70px);
}

.gs-photo--side .gs-photo-tiles {
  margin-top: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 860px) {
  .gs-photo--side .gs-photo-card { grid-template-columns: 1fr; }
  .gs-photo--side .gs-photo-tiles { margin-top: 30px; }
  .gs-photo-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .gs-photo-tiles,
  .gs-photo--side .gs-photo-tiles { grid-template-columns: 1fr; }
}

/* ============================================================
   SERVICE PAGE LAYOUT D: SOLID PANEL WITH ICON GRID
   One block of colour, a call to action on the left, and a ruled
   grid of capabilities on the right.
   ============================================================ */
.gs-panel { padding-block: clamp(48px, 8vh, 100px); }

.gs-panel-card {
  max-width: 1400px;
  margin: 0 auto;
  border-radius: clamp(20px, 2.4vw, 34px);
  padding: clamp(34px, 5vw, 74px);
  display: grid;
  grid-template-columns: minmax(0, .78fr) minmax(0, 1.5fr);
  gap: clamp(30px, 5vw, 80px);
  align-items: center;
  background: linear-gradient(155deg, #A9D68C 0%, #8FC471 52%, #7BB25E 100%);
  color: var(--mm-ink);
}

/* Variant: the same layout in ink, so a second page using this shape
   does not read as a repeat of the first. */
.gs-panel--ink .gs-panel-card {
  background: linear-gradient(155deg, #23271E 0%, #2E3427 55%, #3A422F 100%);
  color: #fff;
}

/* Variant: the ink panel over a photograph. The ink gradient stays as the
   card background, so it is what shows if the image fails rather than a
   bare white box with white text on it. */
.gs-panel--photo .gs-panel-card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.gs-panel-bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  display: block;
}

.gs-panel--photo .gs-panel-bg {
  inset: -20% 0;
  will-change: transform;
}

/* The picture has to be taken out of flow, or as a child of a two column
   grid it would claim a cell and push the content across. */
.gs-panel-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* holds the skyline in frame as the card's height changes with content */
  object-position: center 38%;
}

/* Keep the photograph legible across the whole panel. Text surfaces below
   provide the contrast locally, so the image does not need a heavy wash. */
.gs-panel--photo .gs-panel-card::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(107deg,
      rgba(18, 22, 14, .48) 0%,
      rgba(18, 22, 14, .22) 42%,
      rgba(18, 22, 14, .30) 100%),
    linear-gradient(180deg, rgba(18, 22, 14, .14) 0%, rgba(18, 22, 14, .04) 50%,
      rgba(18, 22, 14, .22) 100%);
}

/* Local glass surfaces keep each text block crisp while leaving the rest of
   the photograph detailed and visible. */
.gs-panel--photo .gs-panel-left,
.gs-panel--photo .gs-panel-cell {
  position: relative;
  z-index: 1;
  background: rgba(18, 22, 14, .42);
  border: 1px solid rgba(255, 255, 255, .16);
  box-shadow: 0 18px 36px rgba(8, 12, 8, .14);
  backdrop-filter: blur(14px) saturate(1.08);
  -webkit-backdrop-filter: blur(14px) saturate(1.08);
}

.gs-panel--photo .gs-panel-left {
  padding: clamp(22px, 3vw, 38px);
  border-radius: 22px;
}

.gs-panel--photo .gs-panel-cell {
  margin: 8px;
  border-radius: 18px;
  border-top: 1px solid rgba(255, 255, 255, .16);
  border-left: 1px solid rgba(255, 255, 255, .16);
}

.gs-panel--photo .gs-panel-cell:nth-child(-n+2),
.gs-panel--photo .gs-panel-cell:nth-child(odd) {
  border-top: 1px solid rgba(255, 255, 255, .16);
  border-left: 1px solid rgba(255, 255, 255, .16);
}

.gs-panel--photo .gs-panel-cell p { opacity: .88; }
.gs-panel--photo .gs-panel-cell i { opacity: .88; }

/* ============================================================
   TABBED CAROUSEL
   A rail of names on the left, a snapping track of cards on the
   right. Without JavaScript it is still a scrollable row, so the
   content is reachable either way.
   ============================================================ */
.gs-tabs { padding-block: clamp(64px, 10vh, 130px); }

.gs-tabs-inner {
  max-width: 1400px;
  margin: 0 auto;
  padding-left: clamp(20px, 4vw, 60px);
  display: grid;
  grid-template-columns: minmax(0, 258px) minmax(0, 1fr);
  column-gap: clamp(24px, 4vw, 70px);
  align-items: start;
}

/* ── the rail ── */
.gs-tabs-nav { padding-top: clamp(60px, 9vw, 128px); }

.gs-tabs-list { list-style: none; margin: 26px 0 0; padding: 0; }

.gs-tab {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  display: block;
  width: 100%;
  padding: 13px 0 13px 18px;
  /* The accent lives on a transparent border, not on a pseudo element, so
     the label never shifts sideways when it becomes active. */
  border-left: 2px solid transparent;
  color: rgba(28, 30, 24, .62);
  font-size: 1rem;
  letter-spacing: -.015em;
  transition: color .3s var(--mm-ease), border-color .3s var(--mm-ease);
}

.gs-tab:hover { color: var(--mm-ink); }

.gs-tab.is-active {
  color: var(--mm-ink);
  font-weight: 600;
  border-left-color: var(--mm-green-deep);
}

.gs-tab:focus-visible { outline: 2px solid var(--mm-ink); outline-offset: 2px; }

/* ── heading ── */
.gs-tabs-main { min-width: 0; }

.gs-tabs-main > h2 {
  font-size: clamp(2rem, 4.6vw, 3.6rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1.02;
  margin: 0 0 clamp(26px, 4vh, 48px);
  max-width: 19ch;
  color: var(--mm-ink);
  padding-right: clamp(20px, 4vw, 60px);
}

.gs-tabs-main > h2 span { color: rgba(28, 30, 24, .40); }

/* ── the track ── */
.gs-tabs-track {
  display: flex;
  gap: clamp(14px, 1.6vw, 24px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* The last card must be able to reach the left edge, which needs trailing
     space of at least (track width - card width). A flat percentage is only
     correct while the card's percentage width applies; once its max-width
     cap binds, the card stops growing and the gap widens. The calc term is
     that case stated exactly, and max() takes whichever is larger. */
  padding: 4px max(18%, calc(100% - 932px)) 4px 0;
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}

.gs-tabs-track::-webkit-scrollbar { display: none; }

.gs-tab-card {
  position: relative;
  flex: 0 0 auto;
  /* Flex items default to min-width:auto, a content-based floor that wins
     over flex-shrink:0 and even over an explicit width — without this, the
     card's own text/art can force it wider than its specified width, which
     was blowing the whole grid track (and everything below it) out past the
     viewport on narrow screens. */
  min-width: 0;
  width: min(1020px, 88%);
  min-height: clamp(380px, 31vw, 500px);
  scroll-snap-align: start;
  border-radius: clamp(18px, 2vw, 30px);
  border: 1px solid rgba(28, 30, 24, .07);
  padding: clamp(30px, 3.6vw, 56px);
  display: grid;
  /* The reference gives the text about 42% and lets the illustration take
     the rest, running to the card's edge. */
  grid-template-columns: minmax(0, .78fr) minmax(0, 1.22fr);
  gap: clamp(16px, 2.4vw, 40px);
  align-items: stretch;
  overflow: hidden;

  /* Frosted, but on a cream base rather than a white one. The renders are
     keyed to a white backdrop and dropped in with multiply, and multiply
     lands on whatever the card's own surface is: over white the backdrop
     stayed white and showed as a rectangle. Over cream it disappears.
     No `isolation` here either, so the blend can reach the surface below. */
  background: linear-gradient(150deg, #F7F4EA 0%, #F2EEE2 55%, #EFEBDE 100%);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  backdrop-filter: blur(20px) saturate(1.2);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    0 22px 50px -34px rgba(28, 30, 24, .45);
}

/* A slow sheen travelling across the pane, the way light moves over glass.
   Only on the card the reader is actually on, so the track is not a row of
   competing highlights. */
.gs-tab-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 30%, rgba(255,255,255,.55) 46%, rgba(255,255,255,.18) 54%, transparent 68%);
  transform: translateX(-130%);
  opacity: 0;
}

.gs-tab-card.is-current::after { animation: gsSheen 2.6s var(--mm-ease) .15s 1; }

@keyframes gsSheen {
  0%   { transform: translateX(-130%); opacity: 0; }
  22%  { opacity: 1; }
  100% { transform: translateX(130%); opacity: 0; }
}

/* The content settles as the card arrives, rather than being there already. */
.gs-tab-card .gs-tab-eyebrow,
.gs-tab-card h3,
.gs-tab-card p,
.gs-tab-card .gs-tab-more { transition: opacity .55s var(--mm-ease), transform .55s var(--mm-ease); }

.gs-tab-card:not(.is-current) .gs-tab-eyebrow,
.gs-tab-card:not(.is-current) h3,
.gs-tab-card:not(.is-current) p,
.gs-tab-card:not(.is-current) .gs-tab-more { opacity: .55; transform: translateY(6px); }

.gs-tab-card.is-current h3 { transition-delay: .06s; }
.gs-tab-card.is-current p { transition-delay: .12s; }
.gs-tab-card.is-current .gs-tab-more { transition-delay: .18s; }

/* The words always read first, on the left, on every card. Alternating the
   illustration between sides makes the eye hunt for the heading each time
   the track moves. */
.gs-tab-body { order: 0; }
.gs-tab-art { order: 1; }

.gs-tab-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* margin-top: auto sinks the copy to the foot of the column, but on a card
   whose heading runs long the column is already full and auto collapses to
   nothing. The padding is the floor: at least this much air under the
   heading on every card, more where there is room. */
.gs-tab-card p {
  margin-top: auto !important;
  padding-top: clamp(26px, 3.4vw, 52px);
}

.gs-tab-eyebrow {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(28, 30, 24, .48);
}

.gs-tab-card h3 {
  font-size: clamp(1.5rem, 2.7vw, 2.5rem);
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1.08;
  margin: 14px 0 0;
  color: var(--mm-ink);
  /* Without a measure the heading sets to one or two words a line in a
     narrow column, which is what made the card so tall. */
  max-width: 15ch;
  text-wrap: balance;
}

.gs-tab-card h3 span { color: rgba(28, 30, 24, .42); }

.gs-tab-card p {
  margin: clamp(20px, 2.4vw, 30px) 0 0;
  font-size: .97rem;
  line-height: 1.6;
  color: rgba(28, 30, 24, .66);
  max-width: 46ch;
}

/* subtle "Read more" affordance under the paragraph — the card itself is
   already the link, so this is a visual cue, not a second interactive
   element. Ghost pill by default; the card's own hover state (not a
   hover on this span) is what darkens it, same trigger as the heading. */
.gs-tab-more {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: clamp(22px, 2.6vw, 34px);
  padding: 9px 9px 9px 18px;
  border-radius: 100px;
  border: 1px solid rgba(28, 30, 24, .16);
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: -.01em;
  color: rgba(28, 30, 24, .70);
  transition: color .35s var(--mm-ease), border-color .35s var(--mm-ease);
}

.gs-tab-more .arr {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(28, 30, 24, .06);
  font-size: .72rem;
  transition: transform .35s var(--mm-ease), background .35s var(--mm-ease);
}

a.gs-tab-card:hover .gs-tab-more {
  color: var(--mm-ink);
  border-color: rgba(28, 30, 24, .32);
}

a.gs-tab-card:hover .gs-tab-more .arr {
  background: var(--mm-green);
  transform: translateX(3px);
}

/* The whole card is the link, so the affordance lives on the card: a lift,
   a deeper shadow and the heading taking the accent. */
a.gs-tab-card {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: transform .4s var(--mm-ease), box-shadow .4s var(--mm-ease),
              border-color .4s var(--mm-ease);
}

a.gs-tab-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 28px 60px -32px rgba(28, 30, 24, .5);
  border-color: rgba(28, 30, 24, .18);
}

a.gs-tab-card:hover h3 { color: #4C7A33; }

a.gs-tab-card:focus-visible { outline: 3px solid var(--mm-ink); outline-offset: 4px; }

.gs-tab-card h3 { transition: color .35s var(--mm-ease); }

/* Touch keeps a hover state stuck on after a tap. */
@media (hover: none) {
  a.gs-tab-card:hover { transform: none; box-shadow: 0 18px 44px -30px rgba(28, 30, 24, .4); }
  a.gs-tab-card:hover h3 { color: var(--mm-ink); }
}

/* The illustration carries the card in the reference, so it fills its column
   and bleeds past the padding to the card's own edge. */
.gs-tab-art {
  min-width: 0;
  display: flex;
  align-items: center;
  margin: calc(clamp(30px, 3.6vw, 56px) * -1);
  margin-left: 0;
}

.gs-tab-img {
  display: block;
  width: 100%;
  mix-blend-mode: multiply;
  animation: gscFloat 7s ease-in-out infinite;
}

.gs-tab-img img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform .6s var(--mm-ease);
}

.gs-tab-card:hover .gs-tab-img img { transform: scale(1.05); }

/* ── progress bar and buttons ── */
.gs-tabs-foot {
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  margin-top: clamp(20px, 3vh, 34px);
  padding-right: clamp(20px, 4vw, 60px);
}

.gs-tabs-bar {
  position: relative;
  flex: 1 1 auto;
  height: 2px;
  background: rgba(28, 30, 24, .14);
  border-radius: 2px;
}

.gs-tabs-bar i {
  position: absolute;
  top: -1px;
  left: 0;
  height: 4px;
  border-radius: 2px;
  background: var(--mm-ink);
  transition: left .25s linear;
}

.gs-tabs-btns { display: flex; gap: 10px; flex: 0 0 auto; }

.gs-tabs-btns button {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid rgba(28, 30, 24, .16);
  background: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  color: var(--mm-ink);
  transition: background .3s var(--mm-ease), opacity .3s var(--mm-ease);
}

.gs-tabs-btns button:hover:not(:disabled) { background: var(--mm-green); }
.gs-tabs-btns button:disabled { opacity: .35; cursor: default; }
.gs-tabs-btns svg { width: 17px; height: 17px; }

@media (max-width: 1000px) {
  .gs-tabs-inner {
    grid-template-columns: 1fr;
    padding-right: 0;
    row-gap: clamp(20px, 3vh, 34px);
  }
  /* Single-column grid now, so .gs-tabs-nav and .gs-tabs-main share one
     track. Without min-width:0 the nav's unwrapped pill row (all six labels
     in a line) became that track's content-based minimum, blowing the whole
     column — and everything sized as a percentage of it, cards included —
     out past the viewport. */
  .gs-tabs-nav { padding-top: 0; min-width: 0; }
  /* The rail becomes a scrolling row of chips: a six item vertical list
     above the cards would push the carousel off the first screen. */
  .gs-tabs-list {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    margin-top: 16px;
    padding-bottom: 4px;
    scrollbar-width: none;
  }
  .gs-tabs-list::-webkit-scrollbar { display: none; }
  .gs-tab {
    width: auto;
    white-space: nowrap;
    padding: 10px 16px;
    border-left: 0;
    border-radius: 999px;
    background: rgba(28, 30, 24, .05);
    min-height: 44px;
  }
  .gs-tab.is-active { background: var(--mm-green); }
  .gs-tab-card { width: min(680px, 88%); }
  .gs-tabs-track { padding-right: max(14%, calc(100% - 672px)); }
}

@media (max-width: 620px) {
  /* Near full-bleed on phones: the card fills the viewport the way the
     reference showcase does, with type and the illustration scaled up
     to match rather than shrunk to a token. Read more stays a plain
     link rather than a heavy pill — a browse list, not a button wall. */
  /* Full-width single-card paging: one card exactly fills the viewport
     (matching the section's usual side gutter) with no sliver of the next
     card in view. The arrow buttons are the way forward from here, not a
     scroll hint — a peeking neighbour was inviting a swipe gesture the
     design doesn't otherwise call out. */
  .gs-tabs-inner { padding-right: clamp(20px, 4vw, 60px); }

  .gs-tab-card {
    width: 100%;
    grid-template-columns: 1fr;
    padding: 30px 26px 34px;
    border-radius: 20px;
    gap: 20px;
  }

  .gs-tabs-track { padding-right: 0; }

  /* 46ch is wider than the card's content box here, and a grid child
     defaults to min-width:auto, so the text ran past the card's edge
     instead of wrapping inside it. */
  .gs-tab-card p {
    max-width: 100%;
    font-size: .98rem;
    line-height: 1.6;
    /* Stacked, margin-top: auto would push the copy to the foot of the card
       and leave a hole under the heading, so a flat gap instead. */
    margin-top: 0 !important;
    padding-top: 18px;
  }

  /* One column here, so the illustration bleeds to both edges, not just one. */
  .gs-tab-art {
    margin: 4px -26px -34px;
    justify-content: center;
  }

  .gs-tab-eyebrow { font-size: .7rem; letter-spacing: .13em; }
  .gs-tab-card h3 { font-size: 1.7rem; margin-top: 12px; max-width: 100%; }

  .gs-tab-img { max-width: 300px; margin: 0 auto; }

  .gs-tab-more {
    margin-top: 20px;
    padding: 0;
    gap: 6px;
    border: 0;
    border-radius: 0;
    font-size: .95rem;
  }

  .gs-tab-more .arr { width: auto; height: auto; background: none; }

  a.gs-tab-card:hover .gs-tab-more .arr { background: none; }

  .gs-tabs-main > h2 { font-size: 1.9rem; margin-bottom: 20px; }
  .gs-tabs-foot { margin-top: 16px; }
  .gs-tabs-btns button { width: 40px; height: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  .gs-tabs-track { scroll-behavior: auto; }
  /* The sheen and the settle are decoration; the card must still be fully
     legible without them, so opacity returns to 1 rather than staying dim. */
  .gs-tab-card.is-current::after { animation: none; }
  .gs-tab-img { animation: none; }
  .gs-tab-card .gs-tab-eyebrow,
  .gs-tab-card h3,
  .gs-tab-card p,
  .gs-tab-card .gs-tab-more,
  .gs-tab-card:not(.is-current) .gs-tab-eyebrow,
  .gs-tab-card:not(.is-current) h3,
  .gs-tab-card:not(.is-current) p,
  .gs-tab-card:not(.is-current) .gs-tab-more {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .gs-tabs-bar i { transition: none; }
}

/* ============================================================
   HOW WE WORK: BENTO GRID
   Replaces the diamond-diagram layout on the service pages.
   One tall card, one wide, two small. The artwork fills each
   card and bleeds behind the text; hover wakes it up.
   ============================================================ */
.gs-bento-grid {
  max-width: 1400px;
  margin: 0 auto;
  padding-inline: 60px;
  display: grid;
  grid-template-columns: 6fr 4fr 4fr;
  grid-template-areas:
    "a b b"
    "a c d";
  gap: clamp(14px, 1.6vw, 22px);
}

.gs-bento-card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-radius: clamp(18px, 2vw, 26px);
  border: 1px solid rgba(28, 30, 24, .09);
  padding: clamp(22px, 2.6vw, 36px);
  min-height: 260px;
  display: flex;
  flex-direction: column;
  background: linear-gradient(160deg, #FDFCF8 0%, #F3F1E8 60%, #EAF0DE 100%);
  box-shadow: 0 16px 40px -30px rgba(28, 30, 24, .35);
  transition: transform .45s var(--mm-ease), box-shadow .45s var(--mm-ease);
}

.gs-bento-card:nth-child(1) {
  grid-area: a;
  min-height: 420px;
  justify-content: flex-end;   /* art above, words at the foot */
}
.gs-bento-card:nth-child(2) { grid-area: b; }
.gs-bento-card:nth-child(3) { grid-area: c; }
.gs-bento-card:nth-child(4) { grid-area: d; }

/* alternating tints, so the grid reads as a set rather than a repeat */
.gs-bento-card:nth-child(2) {
  background: linear-gradient(160deg, #F6F5EE 0%, #E9F1DC 70%, #DDEBC9 100%);
}
.gs-bento-card:nth-child(4) {
  background: linear-gradient(160deg, #FBFAF4 0%, #EFEDE2 100%);
}

.gs-bento-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 30px 60px -32px rgba(28, 30, 24, .45);
}

/* ── artwork layer: behind the words, bleeding off the corner ──
   The renders are opaque files on a near-white backdrop. Every one was
   levelled to the same value before export, so `multiply` drops that
   backdrop into the card and leaves only the object. Without the levelling
   the darker files would each show as a faint rectangle. */
.gs-bento-card .gs-bento-img {
  position: absolute;
  z-index: -1;
  right: -6%;
  bottom: -6%;
  width: 62%;
  min-width: 190px;
  pointer-events: none;
  display: block;
  mix-blend-mode: multiply;
  transition: transform .6s var(--mm-ease);
}

.gs-bento-card:nth-child(1) .gs-bento-img { width: 78%; right: -8%; bottom: -3%; }
.gs-bento-card .gs-bento-img img { width: 100%; height: auto; display: block; }

/* the text must stay readable over the art on the small cards */
.gs-bento-body { position: relative; max-width: 34ch; }

/* ── card chrome ── */
.gs-bento-card i.gs-bento-icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  background: rgba(179, 226, 156, .40);
  color: var(--mm-ink);
  margin-bottom: 16px;
}

.gs-bento-card i.gs-bento-icon gs-icon { display: block; width: 23px; height: 23px; }
.gs-bento-card i.gs-bento-icon svg { width: 100%; height: 100%; display: block; }

.gs-bento-n {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(28, 30, 24, .44);
}

.gs-bento-card h3 {
  font-size: clamp(1.25rem, 2.1vw, 1.7rem);
  font-weight: 500;
  letter-spacing: -.035em;
  line-height: 1.1;
  margin: 10px 0 0;
  color: var(--mm-ink);
  transition: color .35s var(--mm-ease);
}

.gs-bento-card:hover h3 { color: #4C7A33; }

.gs-bento-card p {
  margin: 14px 0 0;
  font-size: .97rem;
  line-height: 1.58;
  color: rgba(28, 30, 24, .62);
  max-width: 30ch;
}

/* ── hover motion, all of it here so reduced-motion can kill it ── */
@keyframes gscFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-9px); }
}

/* The render drifts gently at rest and lifts toward the reader on hover.
   Two separate things: a looping float on the <picture>, and a scale on the
   <img> inside it, so the two transforms never fight over one element. */
.gs-bento-card .gs-bento-img { animation: gscFloat 7s ease-in-out infinite; }
.gs-bento-card:nth-child(2) .gs-bento-img { animation-delay: -1.6s; }
.gs-bento-card:nth-child(3) .gs-bento-img { animation-delay: -3.2s; }
.gs-bento-card:nth-child(4) .gs-bento-img { animation-delay: -4.8s; }

.gs-bento-card .gs-bento-img img { transition: transform .6s var(--mm-ease); }
.gs-bento-card:hover .gs-bento-img img { transform: scale(1.06) translateY(-4px); }

@media (max-width: 960px) {
  .gs-bento-grid {
    grid-template-columns: 1fr;
    grid-template-areas: "a" "b" "c" "d";
  }
  .gs-bento-card:nth-child(1) { min-height: 320px; }
  /* Full width now, so the art no longer needs to fill a tall column. */
  .gs-bento-card .gs-bento-img,
  .gs-bento-card:nth-child(1) .gs-bento-img { width: 48%; right: -6%; bottom: -6%; }
}

@media (max-width: 760px) {
  /* The reference drops the card entirely on phones: illustration, icon,
     title, one paragraph, and air. Boxing each step inside a bordered panel
     on a 440px screen is what made this feel congested, so below this width
     the cards stop being cards and become plain stacked blocks. */
  .gs-bento-grid { gap: clamp(46px, 9vw, 68px); }

  /* Every nth-child has to be named. `.gs-bento-card` is specificity (0,1,0)
     while `.gs-bento-card:nth-child(2)` is (0,2,0), so the alternating tints
     outranked this rule and cards 2 and 4 kept their backgrounds on phones
     while 1 and 3 lost theirs.

     `isolation: auto` is the other half. The base rule isolates the card,
     and `mix-blend-mode: multiply` on the render blends against whatever is
     inside that stacking context. With no card background left, cards 1 and
     3 had nothing to blend into, so the render's white backdrop showed as a
     rectangle. Dropping the isolation lets it blend with the page. */
  .gs-bento-card,
  .gs-bento-card:nth-child(1),
  .gs-bento-card:nth-child(2),
  .gs-bento-card:nth-child(3),
  .gs-bento-card:nth-child(4) {
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    justify-content: flex-start;
    /* The page colour, not `none`. `mix-blend-mode: multiply` needs
       something painted beneath it to blend into; against a transparent
       card there was nothing to multiply and the renders disappeared
       entirely. Matching --mm-cream looks identical to having no card
       while giving the blend a surface. */
    background: var(--mm-cream);
    isolation: isolate;
  }

  .gs-bento-card:hover { transform: none; box-shadow: none; }

  /* Out of the corner and back into the flow, above the words. */
  .gs-bento-card .gs-bento-img,
  .gs-bento-card:nth-child(1) .gs-bento-img {
    position: static;
    /* The base rule sets z-index: -1 to sit the art behind the words. The
       card is a flex container, and z-index applies to flex items even when
       they are static, so that -1 survives `position: static` and buries the
       render behind the card. It has to be cleared explicitly. */
    z-index: auto;
    width: 78%;
    min-width: 0;
    margin: 0 0 clamp(10px, 3vw, 22px);
  }

  .gs-bento-body { max-width: none; }
  .gs-bento-card p { max-width: 38ch; }

  /* Steps alternate side, as in the reference, which stops four stacked
     blocks reading as one long column. */
  .gs-bento-card:nth-child(even) { text-align: right; }
  .gs-bento-card:nth-child(even) .gs-bento-img { margin-left: auto; }
  .gs-bento-card:nth-child(even) i.gs-bento-icon { margin-left: auto; }
  .gs-bento-card:nth-child(even) p { margin-left: auto; }
}

@media (hover: none) {
  /* no hover on touch: the lift and the motion never fire, which is
     correct; the cards are informational, not interactive */
  .gs-bento-card:hover { transform: none; }
}

/* ============================================================
   CASE STUDY: PRODUCT-PAGE LAYOUT
   One idea per screen. Oversized statements, a number row, and
   full-bleed imagery with almost no caption. Everything here is
   scoped to .cs-lean so the older cs- layout is untouched.
   ============================================================ */
.cs-lean { background: var(--mm-cream); }

/* ── opening statement ── */
.cs-hero {
  max-width: 1400px;
  margin: 0 auto;
  padding: clamp(70px, 13vh, 150px) clamp(20px, 4vw, 60px) clamp(40px, 7vh, 80px);
}

.cs-kicker {
  display: block;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .17em;
  text-transform: uppercase;
  color: rgba(28, 30, 24, .45);
}

.cs-lean h1 {
  font-size: clamp(2.8rem, 9vw, 8rem);
  font-weight: 500;
  letter-spacing: -.055em;
  line-height: .95;
  margin: clamp(18px, 3vh, 34px) 0 0;
  color: var(--mm-ink);
  text-wrap: balance;
  max-width: 14ch;
}

.cs-lean h1 em { font-style: normal; color: rgba(28, 30, 24, .38); }

.cs-sub {
  margin: clamp(20px, 3vh, 34px) 0 0;
  font-size: clamp(1.05rem, 1.6vw, 1.4rem);
  line-height: 1.5;
  color: rgba(28, 30, 24, .66);
  max-width: 40ch;
}

/* ── number row ── */
.cs-stats {
  max-width: 1400px;
  margin: 0 auto;
  padding: clamp(30px, 5vh, 60px) clamp(20px, 4vw, 60px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: clamp(24px, 4vw, 60px);
  border-block: 1px solid rgba(28, 30, 24, .12);
}

.cs-stat b {
  display: block;
  font-size: clamp(2.2rem, 4.6vw, 3.6rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1;
  color: var(--mm-ink);
}

.cs-stat span {
  display: block;
  margin-top: 10px;
  font-size: .92rem;
  line-height: 1.45;
  color: rgba(28, 30, 24, .6);
  max-width: 24ch;
}

/* ── a moment: one statement, one image ── */
.cs-moment {
  padding: clamp(60px, 11vh, 150px) 0;
  text-align: center;
}

.cs-moment-copy {
  max-width: 1000px;
  margin: 0 auto;
  padding-inline: clamp(20px, 4vw, 60px);
}

.cs-moment h2 {
  font-size: clamp(2rem, 5.4vw, 4.4rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1.02;
  margin: 0;
  color: var(--mm-ink);
  text-wrap: balance;
}

.cs-moment h2 em { font-style: normal; color: rgba(28, 30, 24, .38); }

.cs-moment p {
  margin: clamp(18px, 2.6vh, 28px) auto 0;
  font-size: clamp(1rem, 1.35vw, 1.15rem);
  line-height: 1.6;
  color: rgba(28, 30, 24, .64);
  max-width: 46ch;
}

/* The image is the payoff, so it gets the room: full width, edge to edge,
   with only the page gutter holding it in. */
.cs-shot {
  margin: clamp(34px, 6vh, 70px) auto 0;
  max-width: 1500px;
  padding-inline: clamp(12px, 2.4vw, 40px);
}

.cs-shot img,
.cs-shot video {
  width: 100%;
  height: auto;
  display: block;
  border-radius: clamp(14px, 1.8vw, 26px);
  box-shadow: 0 30px 70px -40px rgba(28, 30, 24, .45);
}

/* The live 3D viewer sits in a cs-shot slot but is a real element, not an
   image, so it needs the height the old layout gave it back. */
.cs-shot--live .av-wrap { margin: 0; }

.cs-shot--live .av-stage {
  height: min(70vh, 620px);
  border-radius: clamp(14px, 1.8vw, 26px);
  box-shadow: 0 30px 70px -40px rgba(28, 30, 24, .45);
}

.cs-shot--live .av-note { text-align: center; }

@media (max-width: 700px) {
  .cs-shot--live .av-stage { height: min(56vh, 420px); }
}

/* alternating tone, so consecutive moments do not read as one long column */
.cs-moment--tint { background: #F4F1E7; }
.cs-moment--ink { background: #23271E; }
.cs-moment--ink h2 { color: #fff; }
.cs-moment--ink h2 em { color: rgba(255, 255, 255, .42); }
.cs-moment--ink p { color: rgba(255, 255, 255, .68); }

/* ── closing facts, quiet by design ── */
.cs-facts {
  max-width: 1400px;
  margin-inline: auto;
  margin-block: clamp(50px, 9vh, 110px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  /* 1px gaps over a tinted background draw the rules, so no cell needs a
     border and no rule doubles at a seam. */
  gap: 1px;
  background: rgba(28, 30, 24, .12);
  border: 1px solid rgba(28, 30, 24, .12);
  border-radius: 20px;
  overflow: hidden;
}

.cs-fact { background: var(--mm-cream); padding: clamp(20px, 2.6vw, 32px); }

.cs-fact b {
  display: block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(28, 30, 24, .45);
}

.cs-fact span {
  display: block;
  margin-top: 10px;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--mm-ink);
}


@media (max-width: 700px) {
  .cs-lean h1 { max-width: none; }
  .cs-moment { padding-block: clamp(48px, 8vh, 80px); }
  .cs-stats { gap: 26px; }
}


/* The feature rows above these use a flat 60px gutter that drops to 24px at
   1024px. Matching it exactly keeps every section on one edge; a clamp looks
   the same at the extremes but drifts by up to 38px in between. */
@media (max-width: 1024px) {
  .gs-proc-head,
  .gs-proc-grid,
  .gs-bento-grid,
  .gs-caps-inner,
  .gs-split-inner { padding-inline: 24px; }
}

/* ── inline client references ──────────────────────────────
   A client name in running copy means nothing to a reader who
   has not seen the case study, so each one links to it. Styled
   as an underline rather than a colour change, so it stays
   legible on the tinted cards and the dark panel alike. */
.gs-ref {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--mm-green-deep);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: text-decoration-color .3s var(--mm-ease), color .3s var(--mm-ease);
}

.gs-ref:hover {
  color: #4C7A33;
  text-decoration-color: currentColor;
}

.gs-ref:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

/* on the ink panel and the photo cards the accent green is too dark to see */
.gs-panel--ink .gs-ref,
.gs-photo-card .gs-ref { text-decoration-color: var(--mm-green); }
.gs-panel--ink .gs-ref:hover,
.gs-photo-card .gs-ref:hover { color: var(--mm-green); }

@media (prefers-reduced-motion: reduce) {
  .gs-ref { transition: none; }
  .gs-bento-card,
  .gs-bento-card:hover { transform: none; transition: none; }
  .gs-bento-card .gs-bento-img { animation: none; }
  .gs-bento-card .gs-bento-img img,
  .gs-bento-card:hover .gs-bento-img img { transform: none; transition: none; }
  .gs-tab-img img, .gs-tab-card:hover .gs-tab-img img { transform: none; transition: none; }
  .gs-photo-bg,
  .gs-panel--photo .gs-panel-bg {
    inset: 0;
    will-change: auto;
    transform: none;
  }
}

.gs-panel-label {
  display: block;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  opacity: .62;
}

.gs-panel-left h2 {
  font-size: clamp(2rem, 4.6vw, 3.5rem);
  font-weight: 500;
  letter-spacing: -.05em;
  line-height: 1;
  margin: 16px 0 0;
  color: inherit;
}

.gs-panel-cta {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: clamp(26px, 4vh, 40px);
  padding: 16px 30px;
  border-radius: 999px;
  background: #fff;
  color: var(--mm-ink);
  text-decoration: none;
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -.01em;
  transition: transform .4s var(--mm-ease), box-shadow .4s var(--mm-ease);
}

.gs-panel-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 34px rgba(20, 24, 16, .24);
}

.gs-panel-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Rules are drawn as cell borders rather than as gaps over a tinted
   background. The panel sits on a gradient, so a background showing
   through a gap would band across the seams. */
.gs-panel-cell {
  padding: clamp(20px, 2.4vw, 32px);
  border-top: 1px solid rgba(28, 30, 24, .16);
  border-left: 1px solid rgba(28, 30, 24, .16);
}

.gs-panel-cell:nth-child(-n+2) { border-top: 0; }
.gs-panel-cell:nth-child(odd) { border-left: 0; }

.gs-panel--ink .gs-panel-cell {
  border-color: rgba(255, 255, 255, .16);
}

.gs-panel-cell i {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  border: 1px solid currentColor;
  opacity: .72;
}

.gs-panel-cell gs-icon { display: block; width: 22px; height: 22px; }
.gs-panel-cell gs-icon svg { width: 100%; height: 100%; display: block; }

.gs-panel-cell h3 {
  font-size: clamp(1.02rem, 1.5vw, 1.2rem);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.16;
  margin: 16px 0 0;
  color: inherit;
}

.gs-panel-cell p {
  margin: 9px 0 0;
  font-size: .94rem;
  line-height: 1.55;
  opacity: .74;
  color: inherit;
}

@media (max-width: 900px) {
  .gs-panel-card { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .gs-panel-grid { grid-template-columns: 1fr; }
  .gs-panel-cell { border-left: 0; }
  .gs-panel-cell:nth-child(2) { border-top: 1px solid rgba(28, 30, 24, .16); }
  .gs-panel--ink .gs-panel-cell:nth-child(2) { border-top-color: rgba(255, 255, 255, .16); }
}
