/* =========================================================================
   GREEN GRASS — SECTION SPEC + OVERRIDES
   =========================================================================
   Loaded last, so these values win. Figma numbers were read off the nodes in
   frame 253:257 via the plugin API, not sampled from a render.

   ⚠ BOX MODEL RESET AT THE TOP OF THIS FILE — DO NOT REMOVE.
   gg.css never set box-sizing. .gg-wrap sets width:100% AND padding-inline, which
   under the default content-box computes wider than its container, so wrapped
   content overflowed to the right by twice the gutter.

   ⚠ AND READ THIS SECOND PART BEFORE ADDING ANY max-width.
   Adding that reset changed what max-width MEANS on any element that is also a
   .gg-wrap: padding now comes out of the max-width instead of being added to it.
   At desktop the gutter is ~147px per side, so a 68ch text column collapsed to
   roughly half its intended measure. Any max-width on a .gg-wrap element must
   therefore include + var(--gg-gutter) * 2.

   ⚠ NEVER USE overflow:hidden IN THIS FILE — USE overflow:clip.
   hidden makes an element a SCROLL CONTAINER even when nothing can scroll, which
   breaks scroll-driven animations and sticky positioning inside it. clip crops
   identically without that side effect. This bit us three times on one element.

   ⚠ MOBILE TYPE IS SET IN ONE PLACE — the MOBILE TYPE SCALE block near the foot of
   this file. The desktop sizes come from the Figma frames; the mobile sizes are
   deliberately larger and airier than a straight clamp() floor would give, which
   is what makes long service copy readable on a phone. Don't tune individual
   sizes in the section blocks above; change the scale.
   ========================================================================= */

/* ------------------------------------------------------------- box model --- */
.gg, .gg *, .gg *::before, .gg *::after { box-sizing: border-box; }
.gg-wrap { box-sizing: border-box; }

/* ----------------------------------------------------- document clipping --- */
html { overflow-x: clip; }

/* ------------------------------------------------------------ containment -- */
.gg-hero, .gg-intro, .gg-stakes, .gg-pillars, .gg-split, .gg-services,
.gg-blocks, .gg-quote, .gg-process, .gg-faq, .gg-cta, .gg-footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  overflow: clip;
}
.gg-intro > .gg-wrap, .gg-stakes > .gg-wrap, .gg-pillars > .gg-wrap,
.gg-services > .gg-wrap, .gg-blocks > .gg-wrap, .gg-quote > .gg-wrap,
.gg-process > .gg-wrap, .gg-split > .gg-wrap { position: relative; z-index: 2; }

/* ======================================================= CONTENT PHOTOS ==== */
.gg-photo__img,
.gg-photo picture {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.gg-photo picture > img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.gg-photo__img { background: var(--gg-slate); }

/* ⚠ A .gg-photo INSIDE A SIZED MEDIA BOX HAD NO HEIGHT OF ITS OWN.
   .gg-split__media / .gg-services__media / .gg-faq__media take their height from an
   aspect-ratio (or, since the Aug 2026 feedback, from the accordion beside them), but
   the .gg-photo they wrap is a plain block with `height: auto`. Its <img> asks for
   height:100% of an auto-height parent, which resolves back to auto, so the photo
   rendered at its own natural ratio and stopped short of the box. That gap is what
   the design review read as "extra padding at the bottom" and as images not reaching
   the end of the accordion. .gg-block__media and .gg-stakes__media already had this
   fix further down; these three never did. */
.gg-intro__media, .gg-split__media, .gg-services__media, .gg-faq__media { position: relative; }
.gg-intro__media > .gg-photo,
.gg-intro__media > picture,
.gg-split__media > .gg-photo,
.gg-split__media > picture,
.gg-services__media > .gg-photo,
.gg-services__media > picture,
.gg-faq__media > .gg-photo,
.gg-faq__media > picture {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.gg-intro__media .gg-photo__img,
.gg-split__media .gg-photo__img,
.gg-services__media .gg-photo__img,
.gg-faq__media .gg-photo__img {
  width: 100%; height: 100%; object-fit: cover;
}

/* ⚠ PLACEMENT LABELS ARE NOT SHOWN ON THE LIVE SITE.
   gg.css sets `.gg-photo::after { content: attr(data-ml-hero) }`, printing the
   internal DAM placement string over any slot without a photo. It was hidden only
   once a photo was tagged, so with most slots empty most of the site was showing
   internal taxonomy to visitors. /photo-status.html does that job properly. */
.gg-photo::after,
.gg-photo::before { content: none !important; }

/* ================================================ LINKS IN BODY COPY =======
   ⚠ BODY-COPY LINKS HAD NO STYLING AT ALL, so they rendered in the browser's
   default blue and switched to purple once visited. That was invisible until the
   city pages started carrying inline service links — before that, almost every link
   on the site was a button, a nav item or a footer link, all of which set their own
   colour.

   Same root cause as the social icons rendering purple: nothing in gg.css styles a
   plain <a> inside a paragraph, so the user agent decides. :visited is set
   explicitly, because leaving it out is what produces a page of half-purple links.
   =========================================================================== */
.gg p a,
.gg li a,
.gg-faq__a a,
.gg-services__body a,
.gg-acc__body a {
  color: var(--gg-olive);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  transition: color .16s ease;
}
.gg p a:visited,
.gg li a:visited,
.gg-faq__a a:visited,
.gg-services__body a:visited,
.gg-acc__body a:visited { color: var(--gg-olive); }

.gg p a:hover,
.gg li a:hover,
.gg-faq__a a:hover,
.gg-services__body a:hover,
.gg-acc__body a:hover { color: var(--gg-ink); text-decoration-thickness: 2px; }

.gg p a:focus-visible,
.gg li a:focus-visible {
  outline: 2px solid var(--gg-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* On the dark bands the olive is too low-contrast, so links take the accent. */
.gg-pillars p a, .gg-pillars li a,
.gg-process p a, .gg-process li a,
.gg-cta p a, .gg-cta li a,
.gg-footer p a {
  color: var(--gg-accent);
}
.gg-pillars p a:visited, .gg-process p a:visited, .gg-cta p a:visited { color: var(--gg-accent); }
.gg-pillars p a:hover, .gg-process p a:hover, .gg-cta p a:hover { color: #fff; }

/* ⚠ THE FOOTER IS NOT BODY COPY. The `.gg li a` rules above were written for inline
   links inside a paragraph or a bulleted list, but the footer's navigation columns
   are <li><a> too, so they inherited the olive-and-underline treatment and — worse —
   the `:hover { color: var(--gg-ink) }`, which is near-black on the dark footer.
   Hovering a footer link made it vanish. The Aug 2026 review asked for white on
   hover; this restores the muted-cream resting state gg-chrome.css intended and takes
   the hover to white. */
.gg-footer li a,
.gg-footer li a:visited {
  color: var(--gg-on-dark-mut);
  text-decoration: none;
}
.gg-footer li a:hover,
.gg-footer li a:focus-visible {
  color: #fff;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ========================================== CITY PAGE SERVICE LISTS ========
   Built by scripts/fix-schema.js, which turns the doc's "Services include: A, B, C"
   run into a real <ul> with each item linked to its service page. The doc presents
   these as bulleted lists, so this restores its structure.

   Two columns on wider screens: twelve items in a single column pushes the section's
   CTA a long way down the page, and these are short labels rather than sentences.
   =========================================================================== */
.gg-svc-list {
  list-style: none;
  margin: 6px 0 22px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 2px 24px;
}
.gg-svc-list li {
  position: relative;
  padding-left: 18px;
  font-family: var(--gg-body);
  font-size: clamp(16px, 1.2vw, 17px);
  line-height: 1.5;
  color: var(--gg-ink-soft);
  padding-block: 5px;
}
/* Small sage dot, matching the bulleted list treatment in the stakes section. */
.gg-svc-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .95em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--gg-sage);
}
.gg-svc-list li a { color: var(--gg-ink); text-decoration-color: var(--gg-sage); }
.gg-svc-list li a:visited { color: var(--gg-ink); }
.gg-svc-list li a:hover { color: var(--gg-olive); text-decoration-color: var(--gg-olive); }

/* =============================================== SOCIAL ICONS (footer + bar)
   They rendered purple and tiny: inline SVG using currentColor inside an <a> with
   no colour set, so currentColor resolved to the UA link colour. */
.gg-social { display: flex; align-items: center; gap: 10px; }
.gg-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  text-decoration: none; opacity: 1;
  transition: background .16s ease, color .16s ease, border-color .16s ease;
}
.gg-social a svg { width: 17px; height: 17px; display: block; }
.gg-footer .gg-social a { color: #fffffb; border: 1px solid rgba(255, 254, 248, .3); }
.gg-footer .gg-social a:hover,
.gg-footer .gg-social a:focus-visible { background: #c1c28b; border-color: #c1c28b; color: #2d3c39; }
.gg-utility .gg-social a {
  color: var(--gg-ink); border: 1px solid var(--gg-rule);
  width: 30px; height: 30px;
}
.gg-utility .gg-social a svg { width: 15px; height: 15px; }
.gg-utility .gg-social a:hover,
.gg-utility .gg-social a:focus-visible { background: var(--gg-olive); border-color: var(--gg-olive); color: #fffffb; }
.gg-social a:visited { color: inherit; }

/* --------------------------------------------------------- focus visibility -
   gg.css gives buttons and accordion summaries a focus ring but not nav links. */
.gg-nav__link:focus-visible,
.gg-nav__menu a:focus-visible,
.gg-utility a:focus-visible,
.gg-footer a:focus-visible {
  outline: 2px solid var(--gg-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ------------------------------------------------------------------ hero --- */
.gg-hero { display: flex; flex-direction: column; justify-content: flex-end; }
.gg-hero > .gg-wrap,
.gg-hero > .gg-hero__inner {
  position: relative; z-index: 2; margin-top: auto;
  padding-bottom: clamp(36px, 5vw, 76px);
}
.gg-hero h1 { max-width: min(20ch, 100%); }

/* SOME SUB HEROES NEED AN EXPLICIT TOP PAD. Most heroes on the site are a headline
   over a photo and sit comfortably inside the sub hero's 480px min-height. The city
   heroes and the contact hero do not: they carry an eyebrow, a two- or three-line H1,
   a lead paragraph AND a button. That stack is taller than the section, so there is
   no slack left for `margin-top: auto` to absorb and the eyebrow ended up flush
   against the header with no breathing room above it. Padding the top restores the
   gap and lets the section grow instead of crowding its own top edge.
   Keyed off data-page rather than a hero class because the overflow is a property of
   what the page spec puts in the hero, and only these two page keys do it today.
   locations.html shares the service-areas key, but its hero is short: it stays under
   the min-height, keeps its auto top margin and is unchanged. */
body[data-page="service-areas"] .gg-hero > .gg-hero__inner,
body[data-page="contact"] .gg-hero > .gg-hero__inner {
  padding-top: clamp(48px, 6vw, 96px);
}

/* CONTACT HERO — DARKER SCRIM. The shared .gg-hero__scrim in gg.css is deliberately
   light (a designer revision note reads "Reduced opacity of the gradient"), which is
   fine over the darker photos most heroes use. The contact hero's photo is a bright
   sunlit patio with sky across the top third, and the headline's second half is set
   in the sage italic (--gg-accent, #c1c38b) — a light colour on a light ground. Both
   the eyebrow and that italic line were hard to read against it.
   Roughly +.15 alpha at each stop, contact page only, so the reduced gradient the
   designer asked for stays in place on every other hero. If this photo is ever
   swapped for a darker one, this rule is the thing to drop. */
body[data-page="contact"] .gg-hero__scrim {
  background: linear-gradient(180deg, rgba(20,28,26,.40) 0%, rgba(20,28,26,.56) 55%, rgba(20,28,26,.76) 100%);
}

/* ============================================ SPLIT — OVERLAY VARIANT ====== */
.gg-split--overlay { padding-block: clamp(64px, 8vw, 132px); background: var(--gg-slate); }
.gg-split__bg { position: absolute; inset: 0; z-index: 0; }
/* DESIGN FEEDBACK (Aug 2026): "add some subtle opacity to the background image of
   these two sections" — the two homepage overlay bands. A flat scrim over the photo
   rather than opacity on the image itself, so the slate underneath stays solid and
   the cream card keeps its contrast. */
.gg-split__bg::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: rgba(28, 38, 34, .42);
  pointer-events: none;
}
.gg-split__bg > .gg-photo,
.gg-split__bg > picture,
.gg-split__bg .gg-photo__img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.gg-split__card {
  position: relative; z-index: 2;
  background: var(--gg-cream);
  padding: clamp(26px, 3.2vw, 52px);
  max-width: min(560px, 100%);
  text-align: left;
  box-shadow: 0 14px 44px rgba(45, 60, 57, .16);
}
.gg-split__card h2 { margin-bottom: 16px; }
.gg-split__card p { margin-bottom: 14px; }
.gg-split__card p:last-of-type { margin-bottom: 22px; }
.gg-split--overlay-r .gg-split__card { margin-left: auto; }

/* -------------------------------------------------------------- decoration -- */
.gg-watermark {
  position: absolute; top: 50%; left: 50%; translate: -50% -50%;
  width: min(986px, 66%); aspect-ratio: 986 / 747;
  background: url('/img/brand/gg-monogram-inverted.svg') center / contain no-repeat;
  opacity: .03; pointer-events: none; z-index: 0;
}

/* ---- botanical foliage ----------------------------------------------------
   Frame 100:225, nodes 100:246 and 100:264 — the same artwork
   ("All Brand Elements-43" = foliage-sage-43.png) at 3.7deg and -167.13deg. */
.gg-leaf {
  position: absolute; z-index: 0;
  aspect-ratio: 845 / 834;
  background-image: url('/img/brand/foliage-sage-43.png');
  background-repeat: no-repeat; background-size: contain; background-position: center;
  opacity: .25; pointer-events: none;
}
.gg-leaf > path { display: none; }
.gg-leaf--l  { left: -21.2%;  top: -39%;  width: 55.9%; rotate: 3.7deg; }
.gg-leaf--r  { right: -25.7%; top: -70%;  width: 62.9%; rotate: -167.13deg; }
.gg-leaf--rl { right: -25.7%; bottom: -45%; width: 62.9%; rotate: -167.13deg; }

/* ⚠ EDGE BLEED IS OFF — DESIGN FEEDBACK (Aug 2026).
   These pulled the media box out of the container by a full gutter so it ran to the
   browser edge. The designer's note, repeated against the homepage split, the
   services block and every FAQ on the site: "Don't let it touch the edge of the site.
   Make sure it's aligned to the other sections on the page." The classes stay — the
   generator emits them and photo-status keys off them — but they are neutralised in
   one place, so restoring the bleed later is a one-line change here rather than an
   edit to every section template. */
.gg-bleed-r,
.gg-bleed-l,
.gg-bleed-r--deep { margin-inline: 0; }

/* ------------------------------------------- text measures (border-box safe) -- */
.gg-intro:not(.gg-intro--media):not(.gg-intro--wide) .gg-intro__body,
.gg-cta__body,
.gg-quote__body,
.gg-services__head,
.gg-faq__head {
  max-width: calc(78ch + var(--gg-gutter) * 2);
  margin-inline: auto;
}
.gg-intro:not(.gg-intro--media):not(.gg-intro--wide) .gg-intro__body > p,
.gg-cta__body > p,
.gg-services__head > p,
.gg-faq__head > p { max-width: 62ch; margin-inline: auto; }

/* ------------------------------------------------------- type (desktop) ----
   Desktop sizes from the Figma frames. Mobile is handled by the MOBILE TYPE
   SCALE block near the foot of this file — change it there, not here. */
.gg-stakes h2, .gg-split h2, .gg-services h2, .gg-pillars h2,
.gg-process h2, .gg-faq h2, .gg-cta h2, .gg-intro h2 {
  font-size: clamp(26px, 2.6vw, 38px);
  line-height: 1.2;
}
.gg p { font-size: clamp(16px, 1.2vw, 18px); line-height: 1.5; }
.gg .gg-lead { font-size: clamp(17px, 1.25vw, 18px); }

.gg-eyebrow {
  font-family: var(--gg-ui);
  font-weight: 500;
  font-size: clamp(14px, 1.2vw, 18px);
  letter-spacing: .14em;
  text-transform: uppercase;
  margin-bottom: 16px;
}

.gg-btn {
  background: #c1c28b;
  color: #2d3c39;
  font-family: var(--gg-ui);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: .12em;
  min-height: 45px;
  padding: 0 28px;
  border-radius: 50px;
}
.gg-btn:hover { background: var(--gg-olive); color: #fff; }
/* Buttons are links too — keep the body-link rules above off them. */
.gg-btn, .gg-btn:visited, .gg-job__apply, .gg-job__apply:visited { text-decoration: none; }

.gg-block h3 { font-size: clamp(23px, 2.1vw, 30px); line-height: 1.18; margin-bottom: 14px; }

/* --------------------------------------------------- blocks: image height -- */
@media (min-width: 901px) {
  .gg-block { align-items: stretch; }
  .gg-block__media { position: relative; aspect-ratio: auto; min-height: 320px; align-self: stretch; }
  .gg-block__media > .gg-photo,
  .gg-block__media > picture { position: absolute; inset: 0; height: auto; }
  .gg-block__text { display: flex; flex-direction: column; justify-content: center; }
}

/* --------------------------------------------------------------- process -- */
.gg-process__head { display: block; margin-bottom: clamp(26px, 3vw, 44px); }
.gg-process__head h2 { color: #fff; margin-bottom: 18px; }

.gg-step {
  grid-template-columns: 84px minmax(0, 420px) minmax(0, 1fr);
  gap: 0 clamp(16px, 2vw, 32px);
  padding-block: clamp(24px, 2.4vw, 30px);
  border-bottom: 1px solid var(--gg-rule-dark);
  align-items: center;
}
.gg-step:first-of-type { border-top: 1px solid var(--gg-rule-dark); }
.gg-step__label {
  font-family: var(--gg-ui);
  font-weight: 500;
  font-size: clamp(15px, 1.3vw, 18px);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #fffffb;
}
.gg-step p { color: #fffffb; font-size: clamp(16px, 1.2vw, 18px); margin: 0; }

.gg-step__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 50px; height: 46px;
  border: 1px solid rgba(255,254,248,.45);
  border-radius: 50%;
  background: none;
  font-family: var(--gg-jost, var(--gg-ui));
  font-weight: 300; font-size: 22px; font-style: normal;
  color: #fffffb; opacity: 1;
}

/* ---------------------------------------------------------- testimonial ---- */
.gg-quote { background: var(--gg-cream-warm); }
.gg-quote__title { font-family: var(--gg-display); font-size: clamp(26px, 2.6vw, 38px); color: var(--gg-ink); margin-bottom: 26px; }
.gg-quote blockquote {
  font-family: var(--gg-body);
  font-style: normal;
  font-size: clamp(17px, 1.25vw, 18px);
  line-height: 1.55;
  color: var(--gg-ink);
  max-width: 62ch;
  margin-inline: auto;
}
.gg-quote cite {
  font-family: var(--gg-ui);
  font-weight: 500; font-size: 15px;
  letter-spacing: .14em; text-transform: uppercase;
  color: #72795a; margin-top: 30px;
}

/* ----------------------------------------------------------------- FAQ ----- */
.gg-faq summary,
.gg-services summary {
  font-family: var(--gg-ui);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: .10em;
  text-transform: none;
  color: #2d3c39;
  padding: 22px 48px 22px 0;
  line-height: 1.4;
}
.gg-faq details, .gg-services details { border-bottom: 1.1px solid var(--gg-rule); }
.gg-faq__a, .gg-services__body {
  font-family: var(--gg-body);
  font-size: 17px;
  line-height: 1.55;
  color: #2d3c39;
  padding: 0 48px 22px 0;
}
.gg-faq summary::after,
.gg-services summary::after,
.gg-acc summary::after {
  font-family: var(--gg-jost, var(--gg-ui));
  font-weight: 300; font-size: 30px;
  letter-spacing: .02em; color: #2d3c39;
}
.gg-acc summary::after { color: var(--gg-accent); }
.gg-faq details[open] summary::after,
.gg-services details[open] summary::after { content: '\2014'; font-size: 30px; }

/* --------------------------------------------------------------- stakes ----
   PHOTO IS A SQUARE THAT CROPS — it must not drive the row height. Technique from
   the Bertog build: absolute children are out of flow and contribute no height, so
   the square crops whatever photo goes in. */
@media (min-width: 901px) {
  .gg-stakes *:has(> .gg-stakes__text) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(28px, 4vw, 64px);
  }
  .gg-stakes__text { max-width: 54ch; align-self: center; padding-block: 0; }
  .gg-stakes__media {
    position: relative; aspect-ratio: 1; height: auto; min-height: 0; align-self: center;
  }
  .gg-stakes__media > .gg-photo,
  .gg-stakes__media > picture,
  .gg-stakes__media > .gg-photo__img {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  }
  .gg-stakes { padding-block: clamp(44px, 5vw, 84px); }
}

/* ---- ESTD 1995 medallion -------------------------------------------------
   Inside .gg-stakes__media, which is its containing block — `left: 0` plus a -50%
   translate centres it on the photo's left edge, which IS the seam.

   ⚠ NO BASE ROTATION. There used to be `rotate: 180deg` here, on the theory that the
   asset ships upside down. It does not: gg-estd-circle-sage.svg is already the right
   way up, so the 180deg turned it over and "GREEN GRASS / ESTD 1995" read backwards —
   on the homepage and on both /commercial stakes bands. That is the "Rotate logo
   (it's backwards)" note from the Aug 2026 review. The flip animation below still
   owns `transform`, and both its endpoints (0deg, and rotateY(180deg) with
   scaleX(-1), which cancel) now read the right way round. */
.gg-stakes__badge {
  position: absolute; z-index: 3;
  left: 0; top: 50%;
  translate: -50% -50%;
  width: clamp(84px, 9vw, 132px);
  height: auto; aspect-ratio: 1;
  pointer-events: none;
  content: url('/img/brand/gg-estd-circle-sage.svg');
  will-change: transform;
}

/* ---- scroll-driven coin flip ---------------------------------------------
   rotateY with a perspective, or it flattens into a horizontal squash. The badge is
   one <img>, so past 90deg you are looking at its back and the lettering mirrors —
   scaleX(-1) cancels that, swapped AT each 90deg crossing where the coin is edge-on
   and the swap is invisible.

   ⚠ IT IS A FULL 360°, AND THE PHASE IS THE POINT — DO NOT SHORTEN IT TO 180°.
   The timeline is `view()` over `cover 0% cover 100%`, so 50% progress is the moment
   the badge sits in the middle of the viewport. A 0→180deg sweep puts 90deg exactly
   there: the coin is edge-on, and the logo is an unreadable sliver at precisely the
   moment someone is reading the section (reported 22 Sep). A full turn lands 180deg
   at the midpoint instead — face-on, and readable, because the scaleX(-1) un-mirrors
   it — while still reading as a complete flip on the way in and out.

   Three things previously froze this: the `animation` shorthand forcing duration to
   0s, the section being overflow:hidden, and html having overflow-x:hidden. Any
   overflow:hidden between the element and the viewport breaks a scroll timeline. */
@keyframes gg-badge-flip {
  0%     { transform: perspective(900px) rotateY(0deg)     scaleX(1); }
  24.9%  { transform: perspective(900px) rotateY(89.9deg)  scaleX(1); }
  25%    { transform: perspective(900px) rotateY(90.1deg)  scaleX(-1); }
  50%    { transform: perspective(900px) rotateY(180deg)   scaleX(-1); }
  74.9%  { transform: perspective(900px) rotateY(269.9deg) scaleX(-1); }
  75%    { transform: perspective(900px) rotateY(270.1deg) scaleX(1); }
  100%   { transform: perspective(900px) rotateY(360deg)   scaleX(1); }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .gg-stakes__badge {
      animation-name: gg-badge-flip;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}

/* ------------------------------------------------- contact form container --
   The contact band is a two-column form, not a paragraph, so the 78ch reading
   measure set in TEXT MEASURES above starves it. The form column is whatever is
   left after the 380px details column and the gutter: at 1512 that was 184px, so
   every label wrapped onto two lines, the first/last name pair sat at ~80px each
   and the textarea placeholder broke every second word. The band runs to the same
   container width as every other section on the page instead, which gives the form
   ~780px, and margin-inline keeps the whole thing centred and aligned with the
   sections above and below it.

   ⚠ THE :not() PAIR IS LOAD-BEARING, NOT DECORATION. This block used to be three
   plain `.gg-intro__body:has(.gg-contact)` rules. text-align landed, which is why
   the band read as left-aligned, but the max-width never did:
   `.gg-intro:not(.gg-intro--media):not(.gg-intro--wide) .gg-intro__body` counts four
   classes and beats a two-class `.gg-intro__body:has()`, so the reading measure kept
   winning and the form kept its 184px. Matching the measure rule's selector and
   adding :has() on top of it is what makes this override actually apply. Anything
   added here must clear that selector too. */
.gg-intro:not(.gg-intro--media):not(.gg-intro--wide) .gg-intro__body:has(.gg-contact) {
  max-width: calc(var(--gg-container) + var(--gg-gutter) * 2);
  margin-inline: auto;
  text-align: left;
}
.gg-intro:has(.gg-contact) { text-align: left; }
/* Same specificity problem, same fix: the measure block caps a direct <p> child at
   62ch and centres it. The injected form is that child. */
.gg-intro:not(.gg-intro--media):not(.gg-intro--wide) .gg-intro__body:has(.gg-contact) > p {
  max-width: none;
  margin-inline: 0;
}
/* assets/contact-form.html stacks the two columns at 980px. Between there and the
   point where the container stops shrinking, the fixed 380px details column leaves
   the form under 450px and the first-name/last-name row cramps again, so it stacks
   earlier than the fragment does and the form gets the full measure. The selector
   carries .gg-intro__body so it outranks the fragment's own `.gg-contact` media rule,
   which sits in a <style> further down the document and would otherwise win on
   source order. */
@media (max-width: 1180px) {
  .gg-intro__body .gg-contact { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .gg-intro__body .gg-contact__aside { max-width: 620px; }
}

/* ----------------------------------------------------------------- mobile -- */
@media (max-width: 1080px) {
  /* 44px minimum touch target — the drawer holds 27 service links. */
  .gg-nav__menu a { padding: 13px 0; min-height: 44px; display: flex; align-items: center; font-size: 15.5px; }
}

/* =========================================================== MOBILE TYPE ===
   ONE PLACE FOR MOBILE TYPE. Bumped to match the scale Bertog uses on a phone,
   which reads considerably easier than a straight clamp() floor.

   The floor sizes in gg.css were desktop-derived minimums — 15–16px body, 26px h2,
   19px h3 — and on a 390px screen that is small for pages carrying several hundred
   words of service copy. Two changes do the work:

     SIZE        body to 17.5px, leads to 19px, headings up a step
     LINE-HEIGHT 1.6 on body copy, up from 1.42

   Line-height matters as much as size here: at 1.42 the lines sat too close to scan
   comfortably at arm's length.
   =========================================================================== */
@media (max-width: 900px) {
  /* headings */
  .gg h1 { font-size: clamp(34px, 8.6vw, 44px); line-height: 1.14; }
  .gg-stakes h2, .gg-split h2, .gg-services h2, .gg-pillars h2,
  .gg-process h2, .gg-faq h2, .gg-cta h2, .gg-intro h2,
  .gg-quote__title { font-size: clamp(27px, 6.8vw, 34px); line-height: 1.2; }
  .gg-block h3, .gg h3 { font-size: clamp(21px, 5.4vw, 26px); line-height: 1.22; }

  /* body copy */
  .gg p { font-size: 17.5px; line-height: 1.6; }
  .gg .gg-lead { font-size: 19px; line-height: 1.55; }
  .gg-stakes li { font-size: 17.5px; line-height: 1.55; margin-bottom: 12px; }
  .gg-quote blockquote { font-size: 18px; line-height: 1.6; }
  .gg-step p { font-size: 17px; line-height: 1.55; }

  /* Service lists go single column — two 210px columns on a 390px screen would
     cramp both. Items get more vertical room so each is a comfortable tap. */
  .gg-svc-list { grid-template-columns: 1fr; gap: 0; margin-bottom: 24px; }
  .gg-svc-list li { font-size: 17px; padding-block: 8px; }
  .gg-svc-list li::before { top: 1.1em; }

  /* accordions — summary is both a heading and the tap target */
  .gg-faq summary, .gg-services summary { font-size: 16.5px; line-height: 1.45; }
  .gg-acc summary { font-size: 16px; }
  .gg-faq__a, .gg-services__body, .gg-acc__body { font-size: 17px; line-height: 1.6; }

  /* labels and controls */
  .gg-eyebrow { font-size: 13px; letter-spacing: .16em; }
  .gg-step__label { font-size: 15px; }
  .gg-btn { font-size: 15px; min-height: 50px; padding: 0 26px; }
  .gg-quote cite { font-size: 13.5px; }
  .gg-footer li a { font-size: 15.5px; line-height: 1.5; }
  .gg-footer li { margin-bottom: 11px; }
  .gg-footer h2 { font-size: 12px; }
  .gg-legal { font-size: 11px; line-height: 1.5; }

  /* the rest of the mobile layout */
  .gg-bleed-r, .gg-bleed-r--deep, .gg-bleed-l { margin-inline: calc(var(--gg-gutter) * -1); width: auto; }
  .gg-watermark { width: min(986px, 88%); opacity: .04; }
  .gg-hero h1 { max-width: 100%; }
  .gg-hero > .gg-wrap, .gg-hero > .gg-hero__inner { padding-bottom: clamp(28px, 6vw, 48px); }
  body[data-page="service-areas"] .gg-hero > .gg-hero__inner,
  body[data-page="contact"] .gg-hero > .gg-hero__inner { padding-top: clamp(32px, 7vw, 56px); }

  .gg-leaf { opacity: .18; }
  .gg-leaf--l  { left: -26%;  top: -14%;    width: 58%; }
  .gg-leaf--r  { right: -30%; top: -18%;    width: 64%; }
  .gg-leaf--rl { right: -30%; bottom: -14%; width: 64%; }

  .gg-split--overlay { padding-block: clamp(40px, 8vw, 72px); }
  .gg-split__card { max-width: 100%; padding: clamp(22px, 6vw, 32px); }

  .gg-stakes__media { position: relative; aspect-ratio: 4 / 3; height: auto; min-height: 0; }
  .gg-stakes__media > .gg-photo,
  .gg-stakes__media > picture,
  .gg-stakes__media > .gg-photo__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

  /* NO SPIN ON A PHONE — per Billy, 22 Sep. Here the badge hangs off the photo's
     bottom-left corner rather than sitting centred on a seam, and any mid-rotation
     frame reads as a lopsided crescent instead of a coin. Freeze it face-on.
     `transform` is safe to clear because the badge is POSITIONED with `translate`,
     which is a separate property — the flip owns `transform` and nothing else. */
  .gg-stakes__badge {
    left: 8%; right: auto; top: auto; bottom: 0; translate: 0 50%; width: 72px;
    animation: none;
    transform: none;
    will-change: auto;
  }

  .gg-step { grid-template-columns: 50px 1fr; row-gap: 8px; align-items: start; }
  .gg-step p { grid-column: 2; }

  /* Summaries are the main touch target on a phone. */
  .gg-faq summary, .gg-services summary, .gg-acc summary { min-height: 56px; }
}

/* Narrow phones: hold the body size, ease the display type so long headlines don't
   break awkwardly. Body copy is NOT reduced — that's the point of the exercise. */
@media (max-width: 400px) {
  .gg h1 { font-size: 31px; }
  .gg-stakes h2, .gg-split h2, .gg-services h2, .gg-pillars h2,
  .gg-process h2, .gg-faq h2, .gg-cta h2, .gg-intro h2,
  .gg-quote__title { font-size: 25px; }
  .gg-block h3, .gg h3 { font-size: 20px; }
}

@media (max-width: 560px) { .gg-leaf { display: none; } }
@media print { .gg-watermark, .gg-leaf { display: none; } }
