/*
Theme Name: GG-MFG
Description: Custom block theme for the GG-MFG contract-manufacturing lead-gen website.
Version: 1.34.1
Requires at least: 6.4
Requires PHP: 8.0
Text Domain: gg-mfg
*/

/* Fraunces + Geist are enqueued in functions.php, not @import'd here (perf + caching). */

/* ⚠️ Mobile horizontal-overflow guard, added 9/4/26 (Mike: real iPhone screenshots, every
   page zoomed out with the H1 cut off and a horizontal scrollbar). Root cause traced to
   .gg-cred__card (the OCM license tap-card) computing a ~427px width on a 375px viewport --
   a hidden (opacity:0/visibility:hidden, still in normal layout math) absolutely/fixed
   positioned element that's wide enough to inflate the page's effective layout width even
   though it's invisible. html{overflow-x:hidden} is the standard safety net against any
   future instance of the same class of bug (an offscreen/hidden element widening the page)
   -- it doesn't fix the underlying element, just stops it from being able to do this again. */
html { overflow-x: hidden; }

/* Negative letter-spacing above ~32px, per Web Build System §10.1 house craft standard.
   Targets the utility classes WordPress adds automatically when a preset font-size is
   picked (has-{slug}-font-size) -- theme.json has no per-preset letter-spacing field. */
.has-heading-font-size { letter-spacing: -0.01em; }
.has-heading-large-font-size { letter-spacing: -0.02em; }
.has-display-medium-font-size { letter-spacing: -0.03em; }
/* 64px is tight against a 375px viewport for a long word like "Manufacturing" -- not
   technically overflow (no horizontal scroll happens), but it visually crowds the right
   edge on every hero (Mike, 9/4/26, flagged three times on real iPhone screenshots).
   Stepping the size down at narrow widths gives it real breathing room instead of relying
   on word-wrap alone to save it.
   ⚠️ !important required -- WordPress's own generated utility class is
   `.has-display-medium-font-size { font-size: var(--...) !important; }` (core adds
   !important to font-size preset classes, same as it does to color classes -- the exact
   bug that broke the button hover fix earlier this session). A plain override, even in a
   more specific media query, silently loses to it without !important here too. */
@media (max-width: 480px) {
  .has-display-medium-font-size { font-size: 44px !important; }
}
.has-display-large-font-size { letter-spacing: -0.04em; }

/* Positive tracking on small uppercase labels/eyebrows. */
.gg-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--wp--preset--font-family--body);
  font-size: var(--wp--preset--font-size--label);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.gg-eyebrow::before {
  content: "";
  display: inline-block;
  width: 32px;
  height: 3px;
  background: var(--wp--preset--color--green-vivid);
  flex: 0 0 auto;
}
.gg-eyebrow.is-on-light { color: var(--wp--preset--color--green-deep); }
.gg-eyebrow.is-on-dark { color: var(--wp--preset--color--green-vivid); }

/* Italic emphasis pattern -- title phrases wrapped in <em>, colored per section background.
   EXTENDED 9/6/26 [Mike: "whenever you see the italics part of the top hero banner
   section it should be that light green color"] to hero H1s too -- this pairing already
   existed for every body-section heading, heroes just used their own separate className
   (.gg-hero / .gg-hero--light, not .gg-section.is-dark/is-light) so they never matched
   the selector. Same contrast logic carries over: green-vivid (the "light green" accent)
   reads clearly on a dark hero, but that same bright green would wash out on the light
   hero variant's cream background, so light heroes get green-deep instead, exactly like
   a light body section does. */
.gg-section.is-on-light em,
.gg-section.is-light em,
.gg-hero--light em {
  font-style: italic;
  color: var(--wp--preset--color--green-deep);
  font-variation-settings: "SOFT" 30, "opsz" 144;
}
.gg-section.is-on-dark em,
.gg-section.is-dark em,
.gg-hero:not(.gg-hero--light) em {
  font-style: italic;
  color: var(--wp--preset--color--green-vivid);
  font-variation-settings: "SOFT" 30, "opsz" 144;
}

/* Hero inner block is a PLAIN group (see hero.php docblock) so it left-aligns with the
   header instead of self-centering as a narrower column. Line-length capped here, on the
   children, not by re-constraining the block itself. */
.gg-hero__inner > * { max-width: 42rem; }
.gg-hero__inner .wp-block-buttons { max-width: none; }

/* Tighten the hero's own top padding on mobile, ADDED 9/6/26 [Mike, real iPhone
   screenshots: "pages start a bit too far down... seems like a lot of wasted space"].
   Measured on Company Profile at a 375x812 viewport: 94px sticky header + a 24px
   .entry-content margin + this hero's own 64px top padding (var(--wp--preset--spacing--
   section), the same token every section uses for its vertical rhythm) stacked to ~180px
   of dead space before the eyebrow even renders. Only the TOP padding, only on mobile,
   only on the hero -- bottom padding and every other section's spacing (not what was
   flagged) are untouched. !important required: the padding is set via an inline style
   attribute on every *-hero.php pattern (style="padding-top:var(--wp--preset--spacing--
   section)..."), and inline styles beat any external stylesheet rule short of
   !important -- same class of trap as the documented .wp-block-buttons-is-layout-flex
   cascade-tie issue elsewhere in this file. */
@media (max-width: 782px) {
  .gg-hero { padding-top: var(--wp--preset--spacing--medium) !important; }
}

/* Floating isolated-graphic hero variant -- Distribution's own hero, ADDED 9/6/26 (Mike:
   "keep the top area white but I want there to be an isolated graphic on the right side
   on desktop and maybe on mobile it's heavily transparent so the text goes over it").
   Scoped to .has-side-graphic specifically -- NOT applied to .gg-hero--light generally,
   so every other light hero (ab-hero, faq-hero, rq-hero, bap-hero, qc-hero, inv-hero)
   stays exactly as it was. Desktop: the graphic floats in the empty right-hand space at
   its own aspect ratio, vertically centered, behind nothing (the hero copy's own
   max-width already keeps it clear of this column). Mobile: same graphic recentered
   behind the text at heavy transparency, text sits on top via z-index.

   ⚠️ 9/6/26: briefly shrunk and moved this to the bottom of the hero on a hunch that it
   was fighting the heading text -- Mike confirmed that wasn't the actual problem ("the
   image looked fine behind the text, it wasn't fighting at all... you can go back to
   same size image"). Reverted to the original centered/85%-width/12%-opacity treatment.
   The real remaining issue is top spacing, tracked separately below. */
.gg-hero--light.has-side-graphic { position: relative; overflow: hidden; }
.gg-hero--light.has-side-graphic .gg-hero__inner { position: relative; z-index: 1; }
.gg-hero__graphic {
  position: absolute;
  right: 2vw;
  top: 50%;
  transform: translateY(-50%);
  width: clamp(260px, 26vw, 420px);
  height: auto;
  z-index: 0;
  pointer-events: none;
}
@media (max-width: 782px) {
  .gg-hero__graphic {
    right: auto;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 85%;
    max-width: 420px;
    opacity: 0.12;
  }
}

/* Same fix, reusable: a section-intro block (eyebrow + heading) as the SOLE child of an
   align:wide group must not be independently constrained/centered -- same bug as the
   hero, same fix. Used by services-grid.php, meet-the-team.php, and any future pattern
   with an intro block, so it can't reappear by copy-paste again. */
.gg-intro > * { max-width: 42rem; }

/* Section rhythm -- alternating bleed-photo / cream sections, never two bleeds back to back. */
.gg-section { padding-block: var(--wp--preset--spacing--section); }
.gg-section.is-light { background-color: var(--wp--preset--color--cream); color: var(--wp--preset--color--charcoal); }
.gg-section.is-dark { background-color: var(--wp--preset--color--green-darker); color: var(--wp--preset--color--cream); }

/* Scrim for text overlaid on photography -- never rely on the photo alone for contrast. */
.gg-scrim { position: relative; }
.gg-scrim::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(26,46,31,0.15) 0%, rgba(26,46,31,0.9) 100%);
  z-index: 0;
}
.gg-scrim > * { position: relative; z-index: 1; }

/* Buttons -- filled primary, outline secondary. Radius from the custom radius scale.
   The wp:button block puts the className on the OUTER .wp-block-button wrapper, not
   on the .wp-block-button__link anchor that's actually visible as the button -- styling
   .gg-btn itself paints a second box behind WordPress's own default button styling,
   producing a button nested inside a colored halo. Target the inner link instead, and
   neutralize the wrapper so it isn't visually a box of its own. */
.gg-btn { background: none; padding: 0; border-radius: 0; }

/* ⚠️ A NATIVE <button> CARRYING .gg-btn KEEPS ITS USER-AGENT BORDER, 9/15/26 [Mike, on the
   quote form's submit: "that button needs to be the correct stylization and feel of the rest
   of the site. It has some strange line around it."]. The rule above neutralizes the wrapper
   of a wp:button BLOCK, where that wrapper is a <div> and has no border to begin with. But
   the quote form and the configurator both build their buttons as real <button> elements --
   they have to, to submit and to be disabled -- and a <button> brings its own border,
   background, font and color from the UA stylesheet. That border is the line Mike saw.
   Reset the element itself; the inner .wp-block-button__link already carries the entire
   visible treatment, so there is nothing to re-add.

   ⚠️ This also silently fixes every Next/Back/Get-This-Quoted button in the Build a Product
   configurator, which carried the same faint outline for the same reason since 9/4/26. */
button.gg-btn {
  border: none;
  background: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.gg-btn .wp-block-button__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.7em 1.15em;
  border-radius: var(--wp--custom--radius--small);
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
}
.gg-btn.is-primary .wp-block-button__link {
  background: var(--wp--preset--color--green-vivid);
  color: var(--wp--preset--color--green-darker);
}
.gg-btn.is-secondary .wp-block-button__link {
  background: transparent;
  border-color: currentColor;
  color: inherit;
}

/* Hover, ported literally from VX's mechanic (Mike, 9/4/26: "no mouse-over function right
   now on CTA buttons... there should always be one" -- VX applies this to every
   wp:button/wp-element-button, not just the header's .gg-nav__btn, which is why the
   header CTAs already had a hover and nothing else did). */
.wp-element-button,
.wp-block-button__link {
  transition: background-color 150ms ease, color 150ms ease, transform 150ms ease, box-shadow 150ms ease;
}
.wp-element-button:hover,
.wp-block-button__link:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(26,46,31,0.18);
}
.wp-element-button:active,
.wp-block-button__link:active { transform: translateY(0); box-shadow: none; }

/* .is-secondary is an outline button -- VX inverts outline buttons to a solid fill on
   hover rather than just lifting them, and varies the fill by background context (its
   .vx-on-dark modifier). GG has no equivalent context class, but every current
   is-secondary-on-dark usage already carries textColor:"cream" for the same on-dark
   reason, so has-cream-color is used as that same signal instead of adding a new class.

   ⚠️ WordPress's own `.has-cream-color { color: ...!important; }` utility (block color
   support) outranks a same-specificity hover rule's `color` -- background-color flipped
   fine but text color silently stayed cream-on-cream, an invisible white box (Mike,
   9/4/26, live on the homepage hero). `!important` here is the deliberate, commented
   override CLAUDE.md's cascade-tie gotcha calls for, not a habit to repeat elsewhere. */
.gg-btn.is-secondary .wp-block-button__link.has-cream-color:hover {
  background-color: var(--wp--preset--color--cream);
  color: var(--wp--preset--color--green-darker) !important;
}
.gg-btn.is-secondary .wp-block-button__link:not(.has-cream-color):hover {
  background-color: var(--wp--preset--color--charcoal);
  color: var(--wp--preset--color--cream) !important;
}

hr.gg-hairline { border: none; border-top: 1px solid var(--wp--preset--color--hairline); margin: 0; }

/* Inline links inherit theme.json's site-wide link color (green-deep), tuned for light
   backgrounds. Every dark section here also sets textColor:"cream" on its wrapping group
   (has-cream-color), so that same class is reused as the signal to override link color to
   something readable on green-darker/charcoal -- green-deep-on-green-darker is two dark
   greens with barely any contrast, nearly invisible (Mike, 9/4/26, found while fixing the
   footer -- the "Pre-Roll Manufacturing page" link on the Infused Pre-Roll process section
   was almost unreadable). Ported from VX's own fix for the identical problem on its dark
   footer background (its .has-footer-background-color a rule). */
.has-cream-color a:not(.wp-element-button):not(.wp-block-button__link) {
  color: var(--wp--preset--color--cream);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.has-cream-color a:not(.wp-element-button):not(.wp-block-button__link):hover {
  color: var(--wp--preset--color--green-vivid);
}

/* ============================================================================
   NAVIGATION -- custom, replacing core's wp:navigation. Ported from VX's whole nav
   system (Mike, 8/31/26: "similar to the way Vitamix Labs did it, with the mega nav
   stuff"). Markup: patterns/site-nav.php  Data: inc/nav.php  Behaviour: assets/js/nav.js

   ⚠️ THE BREAKPOINT IS 1100px AND IT IS DUPLICATED IN nav.js's matchMedia. Move one, move
   both, or the nav renders inline but behaves like a drawer (or the reverse).

   ⚠️ THE MEGA PANEL NEEDS THE HEADER'S MAIN ROW AS ITS CONTAINING BLOCK, not .gg-nav or
   .gg-nav__item -- left:0/right:0 resolve against the nearest POSITIONED ancestor, and
   without this the panel renders as a vertical ribbon the width of the word "Services".
   .gg-header-main carries position:relative for exactly this (see header.html).
   ============================================================================ */
.gg-header-main { position: relative; }

/* Phone icon -- ported from VX's .vx-nav-phonebtn, INCLUDING the mobile-only gate (Mike,
   9/4/26, correcting a first pass that showed it at every width: "that top banner was
   great on desktop... just needed that fix on mobile"). Above the 1099px drawer
   breakpoint the utility bar already carries the number in full, so the icon would be
   the same action twice -- same reasoning VX's own CSS states for its 782px cutoff. */
.gg-nav-group { column-gap: 0.35rem; }
.gg-nav-phonebtn { display: none; }
@media (max-width: 1099px) {
  .gg-nav-phonebtn {
    display: flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px;
    color: var(--wp--preset--color--green-deep);
    border-radius: var(--wp--custom--radius--medium);
    transition: background-color 150ms ease;
  }
  .gg-nav-phonebtn:hover { background: var(--wp--preset--color--off-white); }
}

.gg-nav__panel { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.25rem); }
.gg-nav__list { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.25rem); margin: 0; padding: 0; list-style: none; }
.gg-nav__item { display: flex; align-items: center; }
.gg-nav__item--sub { position: relative; }

/* .gg-nav__link is either a real <a> (plain leaf items) or a <button> that merges the old
   separate label-link + chevron-disc into one click target (Mike, 9/4/26: Makers Nutrition
   reference -- Services/About only ever open their panel, never navigate). Reset written
   directly on the selector rather than gated to button so both tags render identically. */
.gg-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  /* ⚠️ .gg-nav__link is either a real <a> or a <button> (see note above). appearance:none
     alone did NOT fix the mobile row-height mismatch (Mike, 9/4/26, real iPhone
     screenshot: "the tab seems to work but the padding didn't hit") -- measured the actual
     computed boxes and the real cause is box-sizing: browsers default <button> to
     border-box (part of the UA form-control reset) but <a> has no such default and stays
     content-box. With mobile's min-height:44px, border-box treats padding as INCLUDED in
     that 44px, but content-box adds padding ON TOP of it -- 44px + 28.8px padding = 72.8px,
     exactly the inflated <a> height measured. box-sizing:border-box makes both tags size
     identically. */
  box-sizing: border-box;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-block: 0.35rem;
  padding-inline: 0;
  font: inherit;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.2;
  color: var(--wp--preset--color--charcoal);
  text-decoration: none;
  background: none;
  border: 0;
  margin: 0;
  cursor: pointer;
  transition: color 150ms ease;
  white-space: nowrap;
}
.gg-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--wp--preset--color--green-vivid);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 180ms ease;
}
.gg-nav__link:hover { color: var(--wp--preset--color--green-deep); }
.gg-nav__link:hover::after,
.gg-nav__item.is-open .gg-nav__link::after,
.current-menu-item > .gg-nav__link::after { transform: scaleX(1); }
.gg-nav__item.is-open > .gg-nav__link { color: var(--wp--preset--color--green-deep); }

.gg-nav__chevron { flex: 0 0 auto; transition: transform 180ms ease; }
.gg-nav__item.is-open .gg-nav__chevron { transform: rotate(180deg); }

.gg-nav__ctas { display: flex; align-items: stretch; gap: 0.5rem; }
.gg-nav__btn {
  display: flex; align-items: center;
  padding: 0.7em 1.15em;
  border-radius: var(--wp--custom--radius--medium);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700; line-height: 1.2; text-align: center;
  text-decoration: none; white-space: nowrap;
  background: var(--wp--preset--color--green-vivid);
  color: var(--wp--preset--color--green-darker);
  transition: background-color 150ms ease, transform 150ms ease, box-shadow 150ms ease;
}
.gg-nav__btn:hover { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(26,46,31,0.18); }
.gg-nav__btn:active { transform: translateY(0); box-shadow: none; }
.gg-nav__btn--ghost { background: none; color: var(--wp--preset--color--green-deep); border: 2px solid var(--wp--preset--color--green-deep); }

/* ---------- The mega panel ---------- */
.gg-mega, .gg-drop { position: absolute; z-index: 200; }
.gg-mega {
  top: 100%; left: 0; right: 0;
  background: var(--wp--preset--color--cream);
  border-top: 1px solid var(--wp--preset--color--hairline);
  box-shadow: 0 18px 40px rgba(26,46,31,0.16);
}
.gg-mega__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(240px, 22vw, 300px);
  gap: clamp(1.5rem, 3vw, 3rem);
  max-width: 1170px;
  margin-inline: auto;
  padding: var(--wp--preset--spacing--medium) var(--wp--preset--spacing--base);
}
.gg-mega__cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1.25rem, 2.5vw, 2.5rem); }
.gg-mega__coltitle {
  margin: 0 0 0.9rem;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--wp--preset--color--green-deep);
}
.gg-mega__links { margin: 0; padding: 0; list-style: none; }
.gg-mega__links li { margin: 0; }
.gg-mega__links a {
  display: block; padding-block: 0.4rem;
  font-size: var(--wp--preset--font-size--small); line-height: 1.3;
  color: var(--wp--preset--color--charcoal); text-decoration: none;
  transition: color 140ms ease, transform 140ms ease;
}
.gg-mega__links a:hover { color: var(--wp--preset--color--green-deep); transform: translateX(2px); }

/* ---------- The image-square CTA ---------- */
.gg-mega__cta {
  position: relative; display: flex; align-items: flex-end;
  min-height: 280px; overflow: hidden;
  border-radius: var(--wp--custom--radius--medium);
  text-decoration: none;
  background: var(--wp--preset--color--green-darker);
}
.gg-mega__ctaimg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.55; }
.gg-mega__ctabody {
  position: relative; display: block; width: 100%;
  padding: var(--wp--preset--spacing--base);
  color: var(--wp--preset--color--cream);
}
/* No image (no real photography yet) -- gradient dropped, the flat green-darker bg from
   .gg-mega__cta itself already carries the contrast, no scrim needed for flat color. */
.gg-mega__cta:not(.gg-mega__cta--noimg) .gg-mega__ctabody {
  background: linear-gradient(to top, rgba(26,46,31,0.92) 45%, rgba(26,46,31,0) 100%);
}
.gg-mega__ctaeyebrow {
  display: block; margin-bottom: 0.3rem;
  font-family: var(--gg-font-mono); font-size: var(--wp--preset--font-size--caption);
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--wp--preset--color--green-vivid);
}
.gg-mega__ctatitle { display: block; font-size: var(--wp--preset--font-size--large); font-weight: 700; line-height: 1.25; }
.gg-mega__ctatext { display: block; margin-top: 0.4rem; font-size: var(--wp--preset--font-size--small); line-height: 1.45; color: rgba(248,246,241,0.86); }
.gg-mega__ctalink {
  display: inline-block; margin-top: 0.85rem;
  padding: 0.75rem 1.4rem;
  border-radius: var(--wp--custom--radius--medium);
  background: var(--wp--preset--color--cream);
  color: var(--wp--preset--color--green-darker);
  font-size: var(--wp--preset--font-size--small); font-weight: 700;
  transition: background-color 150ms ease, transform 150ms ease;
}
.gg-mega__cta:hover .gg-mega__ctaimg { opacity: 0.7; }
.gg-mega__cta:hover .gg-mega__ctalink { background: var(--wp--preset--color--green-vivid); transform: translateY(-1px); }

/* ---------- The plain dropdown ---------- */
/* Same visual family as .gg-mega -- same shadow depth, same generous spacing scale, same
   link hover language (color + translateX, no background pill) -- just card-shaped instead
   of edge-to-edge, since a card is the right shape for a short flat list (Mike, 9/4/26:
   "the Services menu has a different feel and look than when I click on About Us"). Only
   the things a card genuinely needs that a full-bleed panel doesn't (a border, a radius,
   a min-width) differ from .gg-mega on purpose. */
.gg-drop {
  top: 100%; left: 0; min-width: 17rem;
  padding: var(--wp--preset--spacing--small);
  background: var(--wp--preset--color--cream);
  border: 1px solid var(--wp--preset--color--hairline);
  border-radius: var(--wp--custom--radius--medium);
  box-shadow: 0 18px 40px rgba(26,46,31,0.16);
}
.gg-drop__links { margin: 0; padding: 0; list-style: none; }
.gg-drop__links a {
  display: block; padding: 0.55rem 0.6rem;
  font-size: var(--wp--preset--font-size--small); line-height: 1.3;
  color: var(--wp--preset--color--charcoal); text-decoration: none;
  transition: color 140ms ease, transform 140ms ease;
}
.gg-drop__links a:hover { color: var(--wp--preset--color--green-deep); transform: translateX(2px); }

/* Desktop-only chrome */
.gg-nav__toggle, .gg-nav__scrim, .gg-nav__item--mobileonly { display: none; }

/* ============================================================
   NAV -- desktop dim-behind-panel (1100px and up)
   Mike, 9/4/26, Makers Nutrition reference: opening the mega/sub panel darkens the page
   content underneath, same shared .gg-nav__scrim element the mobile drawer already uses,
   just toggled on scrim's `hidden` attribute (see nav.js syncScrim()) instead of the
   is-nav-open class.

   ⚠️ FIXED 9/5/26 [Mike: "the top nav sections should not get dark... it looks strange"].
   `inset:0` painted the scrim over the utility bar and main nav row too, not just the page
   content below the header -- z-index:90 alone doesn't save them, since the scrim is a
   DESCENDANT of the header (nested inside .gg-nav), not a sibling positioned outside it.
   Only .gg-mega (its own explicit z-index:200) was high enough to stay above it; the
   utility bar and nav links have no z-index of their own, so they painted underneath the
   scrim within the header's shared stacking context. Fixed by starting the scrim BELOW the
   header instead of fighting stacking order -- `top` uses `--gg-header-h`, measured and
   kept current by nav.js's syncHeaderHeight(), with a generous static fallback for the
   no-JS/pre-measurement instant. */
@media (min-width: 1100px) {
  .gg-nav__scrim:not([hidden]) {
    display: block;
    position: fixed;
    top: var(--gg-header-h, 96px);
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 90;
    background: rgba(26,46,31,0.62);
  }
}

/* ============================================================
   NAV -- drawer mode (below 1100px)
   ============================================================ */
@media (max-width: 1099px) {
  .gg-nav__toggle {
    display: flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: 0 0.5rem;
    background: none; border: 0; color: var(--wp--preset--color--green-deep); cursor: pointer;
  }
  .gg-nav__toggle-bars { display: grid; gap: 4px; }
  .gg-nav__toggle-bars span { display: block; width: 20px; height: 2px; background: currentColor; border-radius: 2px; }

  .gg-nav__scrim { position: fixed; inset: 0; z-index: 998; background: rgba(26,46,31,0.62); }

  /* ⚠️ left, not transform -- a transform-based offscreen offset (translateX(-100%)) is
     paint-only, not a real layout change, and this rendering engine does NOT reliably
     clip that kind of overflow via an ancestor's overflow-x:hidden (confirmed: html{
     overflow-x:hidden} above did nothing for it). The closed drawer's phantom width was
     inflating the whole page's scrollable/layout viewport on mobile Safari, rendering
     every page zoomed out with the H1 cut off (Mike, 9/4/26, real iPhone screenshots).
     Animating `left` (a genuine layout property) instead means the closed state actually
     IS outside the layout, not just painted outside it -- -400px is comfortably beyond
     the panel's own max width (380px) so it's never partially on-screen. */
  .gg-nav__panel {
    position: fixed; top: 0; bottom: 0; left: -400px; z-index: 999;
    box-sizing: border-box; width: min(88vw, 380px);
    padding: var(--wp--preset--spacing--medium) var(--wp--preset--spacing--base);
    background: var(--wp--preset--color--cream);
    box-shadow: 12px 0 44px rgba(26,46,31,0.3);
    overflow-y: auto; overscroll-behavior: contain;
    visibility: hidden;
    transition: left 240ms ease, visibility 240ms;
    display: block;
  }
  .gg-nav.is-nav-open .gg-nav__panel { left: 0; visibility: visible; }
  .gg-nav__list { display: block; }

  .gg-nav__item { display: flex; flex-wrap: nowrap; align-items: center; border-bottom: 1px solid var(--wp--preset--color--hairline); }
  .gg-nav__link {
    flex: 1 1 auto; width: 100%; min-height: 44px;
    justify-content: space-between;
    padding-block: 0.9rem;
    font-size: var(--wp--preset--font-size--medium);
    font-weight: 700; letter-spacing: -0.01em;
    text-align: left; white-space: normal;
  }
  .gg-nav__link::after { display: none; }

  .gg-nav__item--mobileonly { display: flex; border-bottom: 0; }
  .gg-nav__item--mobileonly .gg-nav__link { font-family: var(--gg-font-mono); color: var(--wp--preset--color--green-deep); }

  /* Indent nested submenu content -- previously flush with the top-level item's own left
     edge, no visual hierarchy between "Services" and its own children (Mike, 9/4/26: "a
     slight tab over... some hierarchy to the tabbing over of the sub menu stuff"). */
  .gg-mega, .gg-drop { position: static; width: 100%; border: 0; box-shadow: none; padding: 0 0 0 1.1rem; flex: 0 0 100%; }
  .gg-nav__item--mega, .gg-nav__item--sub { flex-wrap: wrap; }

  .gg-mega__inner { display: block; padding: 0 0 var(--wp--preset--spacing--base); }
  .gg-mega__cols { display: block; }
  .gg-mega__col + .gg-mega__col { margin-top: var(--wp--preset--spacing--base); }
  .gg-mega__coltitle { font-size: var(--wp--preset--font-size--caption); margin-bottom: 0.6rem; }
  .gg-mega__links a, .gg-drop__links a { padding-block: 0.7rem; }

  .gg-mega__cta { display: none; }

  .gg-nav__ctas { display: grid; grid-template-columns: 1fr; gap: 0.6rem; margin-top: var(--wp--preset--spacing--medium); }
  .gg-nav__btn { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .gg-nav__panel { transition: none; }
  .gg-mega__links a:hover { transform: none; }
  .gg-nav__btn:hover { transform: none; }
  .wp-element-button:hover,
  .wp-block-button__link:hover { transform: none; }
}

.gg-noscroll, .gg-noscroll body { overflow: hidden; }

/* ============================================================================
   EXTERNAL-LINK MODAL -- sitewide (Mike, 9/4/26: any off-site link opens here instead of
   a new tab or full navigation, backdrop stays translucent so the site is still visible
   behind it). Markup built and injected by assets/js/external-link-modal.js.
   ============================================================================ */
.gg-extmodal { position: fixed; inset: 0; z-index: 900; }
.gg-extmodal[hidden] { display: none; }
.gg-extmodal__backdrop { position: absolute; inset: 0; background: rgba(23,20,15,0.55); backdrop-filter: blur(2px); }
.gg-extmodal__dialog {
  position: relative;
  margin: clamp(1rem, 4vh, 3rem) auto;
  width: min(94vw, 1120px);
  height: min(88vh, 860px);
  background: var(--wp--preset--color--cream, #FAF7F0);
  border-radius: 14px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,0.45);
}
.gg-extmodal__bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0.6rem 0.6rem 1rem;
  background: var(--wp--preset--color--charcoal, #1A1A1A);
  color: #fff;
}
.gg-extmodal__openlink { color: #fff; font-size: 0.9rem; font-weight: 600; text-decoration: none; opacity: 0.9; }
.gg-extmodal__openlink:hover { opacity: 1; text-decoration: underline; }
.gg-extmodal__close {
  flex: 0 0 auto;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; line-height: 1;
  background: rgba(255,255,255,0.1);
  color: #fff;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}
.gg-extmodal__close:hover { background: rgba(255,255,255,0.22); }
.gg-extmodal__frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }
@media (max-width: 600px) {
  .gg-extmodal__dialog { width: 100vw; height: 100vh; margin: 0; border-radius: 0; }
}

/* ============================================================================
   SPEC TABLE (tag/pill/icon device) -- ported from VX's .vx-spec2 system, Mike, 9/4/26.
   ============================================================================ */
.gg-spec2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(0.85rem, 1.6vw, 1.15rem); margin: var(--wp--preset--spacing--medium) 0 0; }
.gg-spec2__row { padding: 1.15rem 1.25rem; background: var(--wp--preset--color--cream); border: 1px solid var(--wp--preset--color--hairline); border-radius: var(--wp--custom--radius--medium); }
.gg-spec2__head { display: flex; align-items: center; gap: 0.65rem; margin: 0 0 0.75rem; }
.gg-spec2__icon { position: relative; flex: 0 0 auto; width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--wp--preset--color--off-white); color: var(--wp--preset--color--green-deep); }
.gg-spec2__icon--hasinfo { cursor: help; }
.gg-spec2__label { font-size: var(--wp--preset--font-size--small); font-weight: 700; line-height: 1.3; color: var(--wp--preset--color--charcoal); }
.gg-spec2__body { margin: 0; }
.gg-spec2__pills { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.gg-spec2__pill { display: inline-block; background: var(--wp--preset--color--off-white); color: var(--wp--preset--color--green-deep); font-size: var(--wp--preset--font-size--caption); line-height: 1.4; padding: 0.3rem 0.7rem; border-radius: 999px; }
.gg-spec2__notecard {
  position: absolute; top: calc(100% + 10px); left: 50%; transform: translate(-50%, -4px); z-index: 20;
  width: 15rem; padding: 0.75rem 0.9rem;
  background: var(--wp--preset--color--cream); border: 1px solid var(--wp--preset--color--hairline);
  border-radius: var(--wp--custom--radius--medium); box-shadow: 0 10px 30px rgba(26,46,31,0.16);
  font-size: var(--wp--preset--font-size--caption); line-height: 1.5; font-weight: 400;
  color: var(--wp--preset--color--charcoal-soft); text-align: left;
  opacity: 0; visibility: hidden; transition: opacity 160ms ease, transform 160ms ease, visibility 160ms; cursor: auto;
}
.gg-spec2__icon--hasinfo:hover .gg-spec2__notecard,
.gg-spec2__icon--hasinfo:focus .gg-spec2__notecard,
.gg-spec2__icon--hasinfo:focus-within .gg-spec2__notecard { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
@media (max-width: 700px) { .gg-spec2 { grid-template-columns: minmax(0, 1fr); } }

/* The two longer Specs-section explainers (flower tier, cone/paper) sit below the spec
   rows now, side by side on desktop rather than stacked one after the other (Mike,
   9/4/26). is-layout-flow (WordPress's own default layout class on this group) already
   sets each child <p> to full block width -- grid here overrides that per-column. */
/* auto-fit, not a fixed repeat(2,...) -- pages with a registered capacity figure add a
   third item (Mike, 9/4/26: fold the standalone "Capacity" section into this row instead
   of it sitting alone on the page), and this grid needs to hold 2 OR 3 columns depending
   on whether that key is set, not just 2. minmax(220px,1fr) keeps columns from going
   uncomfortably narrow if a third item ever pushes them below a readable width. */
.gg-spec-notes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: clamp(1.5rem, 3vw, 3rem); }
@media (max-width: 700px) { .gg-spec-notes { grid-template-columns: minmax(0, 1fr); } }
.gg-spec-notes__capacity-label {
  margin: 0 0 0.3rem;
  font-family: var(--gg-font-mono);
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--wp--preset--color--green-deep);
}

/* ============================================================================
   FAQ ACCORDION -- ported from VX's .vx-faq (<details>/<summary>, no JS needed).
   ============================================================================ */
.gg-faq__head { align-items: baseline; gap: var(--wp--preset--spacing--base); }
.gg-faq__title { margin: 0; }
.gg-faq__headlink { margin: 0; white-space: nowrap; font-weight: 600; }
.gg-faq { margin-top: var(--wp--preset--spacing--base); border-top: 1px solid var(--wp--preset--color--hairline); }
.gg-faq__item { border-bottom: 1px solid var(--wp--preset--color--hairline); }
.gg-faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: var(--wp--preset--spacing--base);
  padding: var(--wp--preset--spacing--base) 0;
  font-size: var(--wp--preset--font-size--large); font-weight: 700; color: var(--wp--preset--color--green-deep);
  cursor: pointer; list-style: none; transition: color 150ms ease;
}
.gg-faq__q::-webkit-details-marker { display: none; }
.gg-faq__q::after {
  content: "+"; flex: 0 0 auto;
  font-family: var(--gg-font-mono); font-size: var(--wp--preset--font-size--xlarge); font-weight: 400;
  color: var(--wp--preset--color--green-vivid); transition: transform 200ms ease;
}
.gg-faq__item[open] .gg-faq__q::after { content: "\2212"; }
.gg-faq__q:hover { color: var(--wp--preset--color--green-darker); }
.gg-faq__a { padding: 0 0 var(--wp--preset--spacing--base) 0; max-width: 52rem; }
.gg-faq__a p { margin: 0; color: var(--wp--preset--color--charcoal-soft); }

/* ============================================================================
   FULL-IMAGE BACKGROUND BANDS -- ported from VX's .vx-band-bg (Mike, 9/4/26: the pre-roll
   hero banner, "give it that nice background color treatment"). A flat dark band reads as
   a gap; a dark photograph behind the same layout reads as a place. The scrim is
   non-negotiable -- copy must stay legible whatever image sits behind it. Generic, not
   hero-only: any section with className gg-band-bg + an inline background-image gets this
   treatment, so it's ready for every other services page's hero too.
   ============================================================================ */
.gg-band-bg { position: relative; background-size: cover; background-position: center; background-repeat: no-repeat; isolation: isolate; }
/* Mike, 9/4/26: this base (non-hero) scrim is currently only used by the CBD cross-sell
   section's background photo -- every other gg-band-bg usage is a *-hero.php pattern that
   also carries gg-hero, which hits the stronger directional override below instead. First
   pass at 0.86/0.78/0.9 read "too dark already" on the live CBD section, so this is lighter;
   adjust freely without touching the hero override, since nothing else uses this rule. */
.gg-band-bg::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, rgba(26,46,31,0.62) 0%, rgba(26,46,31,0.52) 50%, rgba(26,46,31,0.66) 100%); }
.gg-band-bg > * { position: relative; }
/* Hero variant: the scrim leans harder on the LEFT, where the copy sits, and lifts on the
   right so the photograph stays visible rather than uniformly dimmed -- same directional
   logic as VX's own hero scrim, values ported 1:1 (just navy -> green-darker). */
.gg-hero.gg-band-bg::before {
  background: linear-gradient(100deg, rgba(26,46,31,0.92) 0%, rgba(26,46,31,0.82) 42%, rgba(26,46,31,0.45) 100%);
}
/* Mobile subject-shift override -- some hero photos (AIO, Disposable Vape, Tincture) deliberately
   leave blank negative space on the LEFT for desktop's text-on-left layout, with the actual
   subject (device/pen/bottle) sitting right-of-center in the source photo. Mike, 9/6/26: "on
   mobile... you see nothing" on exactly these three -- center-position cover-cropping on a narrow
   mobile viewport keeps only the horizontal middle of the photo, which is that blank left area,
   cropping the subject out of frame entirely. Shifts the crop window right so the subject stays
   visible. Scoped to a modifier class, not applied sitewide -- other hero photos are busier/more
   centered and don't have this problem; don't add this class to them. */
@media (max-width: 900px) {
  .gg-hero.gg-band-bg.has-subject-right { background-position: 75% center; }
}

/* ============================================================================
   PROCESS RAIL -- ported from VX's .vx-cmsteps--rail (Mike, 9/4/26: "not the right 5-step
   layout... check Vitamix Labs" -- a sequence is the one kind of content where the reader
   is deliberately tracking order, so it's a vertical numbered rail, not a tiled grid).
   ============================================================================ */
.gg-cmsteps { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; margin: var(--wp--preset--spacing--medium) 0 0; padding: 0; list-style: none; position: relative; }
.gg-cmstep { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 1.25rem; align-items: start; padding-bottom: var(--wp--preset--spacing--medium); }
.gg-cmstep:last-child { padding-bottom: 0; }
.gg-cmstep:not(:last-child)::before {
  content: ""; position: absolute; left: 1.3rem; top: 2.9rem; bottom: 0.35rem; width: 2px;
  background: var(--wp--preset--color--hairline);
}
.gg-cmstep__body { max-width: 46rem; }
.gg-cmstep__n {
  position: relative; z-index: 1; display: flex; align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  background: var(--wp--preset--color--green-vivid); color: var(--wp--preset--color--green-darker);
  font-family: var(--gg-font-mono); font-size: var(--wp--preset--font-size--medium); font-weight: 700; line-height: 1;
}
.gg-cmstep__title { margin: 0.35rem 0 0.4rem; font-size: var(--wp--preset--font-size--medium); font-weight: 700; line-height: 1.25; }
.gg-cmstep__text { margin: 0; font-size: var(--wp--preset--font-size--small); line-height: 1.6; opacity: 0.85; }
.gg-cmstep__text a { color: inherit; text-decoration: underline; }

/* ============================================================================
   SERVICE PAGE building blocks -- sub-hero (one column) and "way" cards, shared across
   all 8 services pages, not just pre-roll.
   ============================================================================ */
.gg-subhero__inner > * { max-width: 42rem; }
.gg-way-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--wp--preset--spacing--small); margin-top: var(--wp--preset--spacing--medium); }
.gg-way-card { background: var(--wp--preset--color--cream); border: 1px solid var(--wp--preset--color--hairline); border-radius: var(--wp--custom--radius--large); overflow: hidden; }
.gg-way-card__media { aspect-ratio: 4/3; background: var(--wp--preset--color--green-darker); overflow: hidden; }
.gg-way-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gg-way-card__body { padding: var(--wp--preset--spacing--base); }
.gg-way-card__title { font-size: var(--wp--preset--font-size--medium); font-weight: 700; color: var(--wp--preset--color--charcoal); margin: 0 0 0.5rem; }
/* Icon-headed card variant (ipr-infusion-types.php) -- icon chip + title share a row,
   title's own bottom margin moves onto the row instead so the icon stays vertically
   centered against a single line of text. */
.gg-way-card__head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
.gg-way-card__head .gg-way-card__title { margin: 0; }
.gg-way-card__body p { margin: 0; color: var(--wp--preset--color--charcoal-soft); }
.gg-way-card__body a { color: var(--wp--preset--color--green-deep); }
@media (max-width: 900px) { .gg-way-cards { grid-template-columns: 1fr; } }

.gg-image-band { border-radius: var(--wp--custom--radius--large); overflow: hidden; }
.gg-image-band img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- Section image sidebar -- ported 9/5/26 from VX's .vx-liquid__split system
   (Mike: "images on the right, then images on the left, never both on the same side
   section to section... always to the side... just 1 image in each section, never
   more"). VX's own comment on that file calls it "THE SITE-WIDE STANDARD FOR PAGE
   IMAGERY" -- same rule, same mechanism, ported rather than re-invented: a narrow
   sidebar image (220-340px) beside the text, NOT a near-even 44/56 or 48/52 split.
   `.gg-liquid__split--reverse` flips which side the image sits on -- pass it on every
   OTHER split down a given page so two in a row never land on the same side. Exactly
   one image per split; a section needing two real photos gets two separate splits
   (on two different sections), not one split with a pair. ---------- */
.gg-liquid__split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(220px, 24vw, 340px);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.gg-liquid__split--reverse { grid-template-columns: clamp(220px, 24vw, 340px) minmax(0, 1fr); }
.gg-liquid__split--reverse .gg-liquid__body { order: 2; }
.gg-liquid__split--reverse .gg-liquid__pic { order: 1; }
.gg-liquid__body { max-width: 46rem; }
.gg-liquid__pic { margin: 0; border-radius: var(--wp--custom--radius--large); overflow: hidden; }
.gg-liquid__pic img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }

/* Collage variant of .gg-liquid__pic -- three photos stacked to fill a MUCH taller sidebar
   than one image can without either stretching badly or leaving huge gaps top/bottom
   (pr-process.php: a 6-step rail runs far taller than the standard single-image slot).
   Mike, 9/5/26: "always better to have a tall image here... not something that when cropped
   on mobile looks stupid... make a long collage out of [3 photos] looking like photographs,
   same as Vitamix Labs." Ported the SPIRIT of VX's .vx-founding-collage (white-bordered,
   slightly rotated, reads as loose photographs) but not its exact absolutely-positioned
   1:1-square mechanic -- that shape doesn't fit a tall narrow sidebar. This is a vertical
   flex stack instead, filling whatever height the text column sets via align-self:stretch,
   so it genuinely reads as ONE tall collage rather than one centered photo. Row instead of
   stack on mobile, where the sidebar collapses into a full-width band above the text -- a
   tall narrow stack squeezed into that shallow band would crop each photo to a sliver. */
.gg-liquid__pic--collage { overflow: visible; border-radius: 0; align-self: stretch; }
.gg-liquid__collage { display: flex; flex-direction: column; gap: 0.7rem; height: 100%; }
.gg-liquid__collage img {
  flex: 1 1 0; min-height: 0; width: 100%; aspect-ratio: auto; object-fit: cover; display: block;
  border: 5px solid #fff; box-shadow: 0 10px 24px rgba(26,46,31,0.22); border-radius: 2px;
}
.gg-liquid__collage img:nth-child(1) { transform: rotate(-1.4deg); }
.gg-liquid__collage img:nth-child(2) { transform: rotate(1deg); }
.gg-liquid__collage img:nth-child(3) { transform: rotate(-0.8deg); }
/* ⚠️ FIXED 9/5/26 [Mike, from real mobile screenshots: "breaks the fixed width... goes
   three across"]: flex-direction:row put three square photos (each with a 5px border) side
   by side at full-ish width each -- their combined natural width overflowed the viewport
   and bled off the right edge instead of wrapping, since flex items don't shrink below
   their content size by default. Fixed by switching to the SAME absolutely-positioned
   overlapping mechanic VX's own founding-collage uses (see this block's opening comment) --
   bounded inside a relative container sized as a PERCENTAGE of viewport width, so three
   overlapping photos physically cannot exceed 100% width regardless of their individual
   size. Reads as a real scattered scrapbook collage instead of a strict grid, which was the
   original ask anyway ("overlap kinda like a real collage"). */
@media (max-width: 900px) {
  .gg-liquid__pic--collage { align-self: auto; }
  .gg-liquid__collage { position: relative; display: block; height: auto; aspect-ratio: 1 / 1; width: 100%; }
  .gg-liquid__collage img { position: absolute; flex: none; width: 60%; min-height: 0; }
  .gg-liquid__collage img:nth-child(1) { aspect-ratio: 4 / 3; top: 2%; left: 0; z-index: 1; transform: rotate(-4deg); }
  .gg-liquid__collage img:nth-child(2) { aspect-ratio: 1 / 1; bottom: 2%; right: 0; z-index: 2; transform: rotate(3deg); }
  .gg-liquid__collage img:nth-child(3) { width: 52%; aspect-ratio: 4 / 3; top: 32%; left: 24%; z-index: 3; transform: rotate(-2deg); }
}

@media (max-width: 900px) {
  .gg-liquid__split { grid-template-columns: minmax(0, 1fr); gap: var(--wp--preset--spacing--medium); }
  .gg-liquid__pic { order: -1; }
  .gg-liquid__split--reverse .gg-liquid__body { order: 2; }
  .gg-liquid__split--reverse .gg-liquid__pic { order: -1; }
}

/* Utility bar -- ported from VX's .vx-utility strip, values read directly from its CSS
   rather than approximated. Restored 9/4/26 after a wrong first pass deleted it entirely
   (see header.html's comment on the utility bar for the full correction). */
.gg-utility__note { margin: 0; color: var(--wp--preset--color--charcoal-soft); }
.gg-utility__phone {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  text-decoration: none;
  color: var(--wp--preset--color--green-deep);
  white-space: nowrap;
}
.gg-utility__phone-label { color: var(--wp--preset--color--charcoal-soft); font-size: var(--wp--preset--font-size--caption); }
.gg-utility__phone-num {
  font-family: var(--gg-font-mono);
  font-size: var(--wp--preset--font-size--base);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.gg-utility__phone:hover .gg-utility__phone-num { color: var(--wp--preset--color--green-vivid); }
/* Whole bar hides below the nav drawer breakpoint now, not just the note text -- it was
   rendering alongside .gg-nav-phonebtn on mobile (Mike, 9/4/26 screenshot: both the bar
   AND the icon showing at once), the exact redundancy both were built to avoid. */
@media (max-width: 1099px) { .gg-utility-bar { display: none; } }

/* Sticky header -- the "fun transition" (Mike, 8/31/26). Ported exactly: sticky lives on
   the template-part WRAPPER, not on the inner <header>, because WordPress sizes that
   wrapper to its content -- sticky on the inner element has zero distance to travel and
   is silently inert. Shadow is ALWAYS on, not scroll-triggered (VX's own note: the
   scroll-triggered version needs a JS class on <body>, a silent failure point for a
   purely decorative effect -- a constant shadow costs nothing and cannot break). The
   phone icon (.gg-nav-phonebtn) is now the thing this keeps reachable at any scroll
   depth -- the utility bar it used to be true of is gone (9/4/26). */
.wp-site-blocks > header.wp-block-template-part { position: sticky; top: 0; z-index: 100; box-shadow: 0 1px 12px rgba(26,46,31,0.14); }
/* Ported from VX -- skipped this the first time, and it's exactly why the header
   overlapped the WordPress admin toolbar and looked broken on scroll for a logged-in
   viewer (Mike, 8/31/26: "it looks like it breaks apart when you scroll down"). The
   admin bar is also position:fixed at top:0, so without this offset the two compete for
   the same 0px and the sticky header renders underneath/through it once scrolled. */
.admin-bar .wp-site-blocks > header.wp-block-template-part { top: 32px; }
@media (max-width: 782px) { .admin-bar .wp-site-blocks > header.wp-block-template-part { top: 46px; } }

/* Monospace stack for identifier-like values (license numbers) -- no mono webfont loaded,
   system stack is legible enough for this and avoids a third font-loading request. */
:root { --gg-font-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace; }

/* ============================================================================
   MOSAIC / TILE SYSTEM -- ported from VX's capability-grid mechanic (Mike, 8/31/26:
   "very similar in layout and feel" to VX). Image fills the tile, label + link sit on
   top of a bottom-weighted scrim, one feature tile spans two columns in brand color.
   No real photography exists yet for GG -- tiles use a flat tint in place of
   .gg-tile__img rather than invented stock imagery; swap in a real <img> per tile once
   facility/product photography exists, the markup and scrim are already built for it.
   ============================================================================ */
.gg-mosaic {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--wp--preset--spacing--small);
  margin-top: var(--wp--preset--spacing--medium);
}
.gg-tile {
  position: relative;
  display: block;
  min-height: 300px;
  overflow: hidden;
  border-radius: var(--wp--custom--radius--large);
  text-decoration: none;
  isolation: isolate;
  background-color: var(--wp--preset--color--green-darker);
}
.gg-tile__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
/* Scrim -- overlaid text must never rely on a photo alone for contrast. */
.gg-tile:not(.gg-tile--feature)::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(26,46,31,0) 0%, rgba(26,46,31,0.1) 40%, rgba(26,46,31,0.6) 68%, rgba(26,46,31,0.9) 100%);
}
.gg-tile:hover .gg-tile__img { transform: scale(1.05); }
.gg-tile__body { position: absolute; inset: auto 0 0 0; display: flex; flex-direction: column; gap: 0.4rem; padding: var(--wp--preset--spacing--base); }
.gg-tile__title { color: var(--wp--preset--color--cream); font-size: var(--wp--preset--font-size--xlarge); font-weight: 700; line-height: 1.15; letter-spacing: -0.01em; }
.gg-tile__link { color: var(--wp--preset--color--green-vivid); font-size: var(--wp--preset--font-size--small); font-weight: 600; transition: color 150ms ease; }
.gg-tile:hover .gg-tile__link { color: var(--wp--preset--color--cream); }

/* Multi-link tile variant, ADDED 9/6/26 [Mike: "you can't have an our services link
   anywhere on the site" caught that the merged "Vapes" tile linked to a nonexistent
   /services/ hub page -- no single vape page (AIO/Disposable/Cartridge) fairly stands
   in for all three, and the same audit found the merged "Infused Pre-Rolls" tile never
   linked Infused & Coated Pre-Roll at all]. Not one full-card link guessing at "the"
   page -- a short list of real named links to each actual page, inside the same visual
   card. cursor:default on the card itself since (unlike every other tile) the card as a
   whole isn't a single click target anymore, only the links inside it are. */
.gg-tile--multi { cursor: default; }
.gg-tile__multilinks { display: flex; flex-direction: column; gap: 0.25rem; }
.gg-tile__multilinks a {
  color: var(--wp--preset--color--green-vivid);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  text-decoration: none;
  transition: color 150ms ease;
}
.gg-tile__multilinks a:hover { color: var(--wp--preset--color--cream); text-decoration: underline; }

/* Feature tile: brand color, spans two columns, carries the primary CTAs. */
.gg-tile--feature { grid-column: span 2; background: var(--wp--preset--color--green-deep); }
.gg-tile--feature .gg-tile__body { inset: 0; justify-content: center; align-items: center; text-align: center; gap: 0.85rem; padding: var(--wp--preset--spacing--medium); padding-top: calc(var(--wp--preset--spacing--medium) + 0.75rem); padding-bottom: calc(var(--wp--preset--spacing--medium) + 0.75rem); }
.gg-tile__feature-title { color: var(--wp--preset--color--cream); font-size: var(--wp--preset--font-size--heading); font-weight: 700; line-height: 1.15; letter-spacing: -0.02em; }
.gg-tile__feature-sub { color: var(--wp--preset--color--cream); opacity: 0.85; font-size: var(--wp--preset--font-size--base); }
.gg-tile__ctas { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; margin-top: 0.4rem; }
.gg-tile__btn {
  display: inline-block;
  padding: 0.75em 1.4em;
  border-radius: var(--wp--custom--radius--small);
  border: 2px solid transparent;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  text-decoration: none;
  transition: background-color 150ms ease, transform 150ms ease;
}
.gg-tile__btn--solid { background: var(--wp--preset--color--green-vivid); color: var(--wp--preset--color--green-darker); }
.gg-tile__btn--solid:hover { transform: translateY(-1px); }
.gg-tile__btn--ghost { background: transparent; border-color: rgba(248,246,241,0.7); color: var(--wp--preset--color--cream); }
.gg-tile__btn--ghost:hover { background: var(--wp--preset--color--cream); color: var(--wp--preset--color--green-darker); }

@media (max-width: 1024px) {
  .gg-mosaic { grid-template-columns: repeat(2, 1fr); }
  .gg-tile--feature { grid-column: span 2; }
}
@media (max-width: 600px) {
  .gg-mosaic { grid-template-columns: 1fr; }
  .gg-tile { min-height: 240px; }
  /* ⚠️ The feature tile's body is position:absolute (inset:0), so it never contributes to
     .gg-tile's own height -- the box's rendered height comes ENTIRELY from min-height.
     The shared 240px above fits a plain tile's short title+link, but the feature tile
     stacks a title, a subhead, AND two buttons; at 240px that content was taller than the
     box and .gg-tile's overflow:hidden silently clipped it, cutting off the Request Quote
     button (Mike, 9/4/26, real iPhone screenshot). Its own taller floor instead of the
     shared one. */
  .gg-tile--feature { grid-column: span 1; min-height: 380px; }
}
@media (prefers-reduced-motion: reduce) {
  .gg-tile:hover .gg-tile__img { transform: none; }
}

/* ============================================================================
   CLAIM BAND -- ported from VX's .vx-claimband. Deliberately quiet: a tint, centered text,
   no button. Its whole job is to be a beat between the hero and the argument.
   ============================================================================ */
.gg-claimband__text {
  margin: 0;
  max-width: 60rem;
  margin-inline: auto;
  text-align: center;
  font-size: var(--wp--preset--font-size--large);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--wp--preset--color--charcoal);
}
@media (max-width: 781px) {
  .gg-claimband__text { font-size: var(--wp--preset--font-size--base); }
}

/* ============================================================================
   TRUST BAR -- ported from VX's trust-bar.php mechanic. Two deliberately different
   treatments (same distinction VX draws): .gg-cred is a real credential with a
   regulator behind it and is allowed to look like a mark; .gg-proof is a locked fact
   and must never be seal-shaped. Raw HTML, not block markup, so it can hand-build the
   exact container width and the hover/focus-reveal card.
   ============================================================================ */
.gg-trust {
  /* No max-width/margin:auto here (VX's own version has this, sized against a container
     WITHOUT the wide-alignment wrapper this one sits inside) -- with both in play here,
     .gg-trust centered ITSELF independently of the align:wide wrapper around it, landing
     at a different left edge (175px) than every other section's content (93px). Filling
     100% of its wrapper's already-correct width is the actual fix, not a second attempt
     at centering. */
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--wp--preset--spacing--medium);
  padding: var(--wp--preset--spacing--base) var(--wp--preset--spacing--medium);
  background: var(--wp--preset--color--cream);
  border: 1px solid var(--wp--preset--color--hairline);
  border-radius: var(--wp--custom--radius--large);
}
.gg-trust__creds { display: flex; flex-wrap: wrap; align-items: center; gap: var(--wp--preset--spacing--base); }
.gg-cred { display: flex; align-items: center; }
/* Real NYS OCM seal is a wide wordmark (768x147, ~5.2:1), not a badge shape -- sized by
   height like VX's FDA mark, width follows the image's own aspect ratio. */
.gg-cred__mark { height: 40px; width: auto; display: block; }
.gg-cred--type { flex-direction: column; align-items: flex-start; gap: 0.1rem; padding-left: var(--wp--preset--spacing--base); border-left: 1px solid var(--wp--preset--color--hairline); }
.gg-cred__title { font-size: var(--wp--preset--font-size--base); font-weight: 700; color: var(--wp--preset--color--charcoal); letter-spacing: -0.01em; }
.gg-cred__sub { font-family: var(--gg-font-mono); font-size: var(--wp--preset--font-size--caption); color: var(--wp--preset--color--charcoal-soft); }

/* flex-basis:0% (not auto), plus min-width:0 -- a `display:grid` flex item resolves
   flex-basis:auto to its MAX-CONTENT size (the widest its 1fr tracks could ever want),
   and empirically still won't shrink below that even with min-width:0 -- confirmed via
   getComputedStyle: min-width read 0px yet width stayed pinned at 1170px, its full
   unconstrained content width, forcing a wrap next to the credential block instead of
   sharing the row. flex-basis:0% starts the item at zero and lets flex-grow:1 hand it
   real available space instead, which the grid's 1fr tracks then actually divide. */
.gg-trust__proof { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; gap: var(--wp--preset--spacing--small); flex: 1 1 0%; min-width: 0; }
/* Off-white, not cream (=white) -- these cards need to read as distinct from the white
   .gg-trust card they sit inside (Mike, 8/31/26: "same with behind the 3 icons"), same
   role VX's own light-gray .vx-proof cards play against its white trust-bar card. */
.gg-proof { display: flex; flex-direction: column; justify-content: center; gap: 0.3rem; padding: var(--wp--preset--spacing--base) var(--wp--preset--spacing--small); background: var(--wp--preset--color--off-white); border: 1px solid var(--wp--preset--color--hairline); border-radius: var(--wp--custom--radius--medium); text-align: center; }
.gg-proof__value { font-size: var(--wp--preset--font-size--xlarge); font-weight: 700; color: var(--wp--preset--color--green-deep); letter-spacing: -0.02em; line-height: 1.05; }
.gg-proof__label { font-size: var(--wp--preset--font-size--caption); color: var(--wp--preset--color--charcoal-soft); line-height: 1.35; }

@media (max-width: 900px) {
  .gg-trust { flex-direction: column; align-items: stretch; gap: var(--wp--preset--spacing--base); }
  .gg-trust__creds { flex-wrap: nowrap; justify-content: center; gap: var(--wp--preset--spacing--small); }
  .gg-cred__mark { height: 32px; }
  .gg-cred--type { padding-left: var(--wp--preset--spacing--small); }
  .gg-trust__proof { grid-template-columns: 1fr; }
}

/* OCM license card -- click/tap-to-expand, same mechanic as VX's FDA badge: no hover on
   touch, so it opens on tap via tabindex + :focus-within, not JS. */
.gg-cred--hasinfo { position: relative; cursor: help; padding: 0.5rem 0.75rem; margin: -0.5rem -0.75rem; border-radius: var(--wp--custom--radius--medium); }
.gg-cred__card {
  position: absolute;
  top: calc(100% + 12px);
  left: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  width: 20rem;
  padding: var(--wp--preset--spacing--base);
  background: var(--wp--preset--color--cream);
  border: 1px solid var(--wp--preset--color--hairline);
  border-top: 3px solid var(--wp--preset--color--green-vivid);
  border-radius: var(--wp--custom--radius--large);
  box-shadow: 0 10px 30px rgba(31,36,33,0.18);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 160ms ease, transform 160ms ease, visibility 160ms;
}
.gg-cred--hasinfo:hover .gg-cred__card,
.gg-cred--hasinfo:focus .gg-cred__card,
.gg-cred--hasinfo:focus-within .gg-cred__card { opacity: 1; visibility: visible; transform: translateY(0); }
.gg-cred__card-title { font-size: var(--wp--preset--font-size--base); font-weight: 700; color: var(--wp--preset--color--green-deep); }
.gg-cred__rows { display: block; margin-top: 0.6rem; }
.gg-cred__row { display: block; }
.gg-cred__row + .gg-cred__row { margin-top: 0.5rem; }
.gg-cred__k { display: block; font-size: var(--wp--preset--font-size--caption); letter-spacing: 0.05em; text-transform: uppercase; color: var(--wp--preset--color--charcoal-soft); }
.gg-cred__v { display: block; font-size: var(--wp--preset--font-size--small); font-weight: 600; line-height: 1.35; color: var(--wp--preset--color--charcoal); font-family: var(--gg-font-mono); }

@media (max-width: 600px) {
  .gg-cred__card { position: fixed; top: auto; bottom: 1.5rem; left: 1rem; right: 1rem; width: auto; max-width: calc(100vw - 2rem); box-sizing: border-box; }
}

/* --- Discoverability hint, ported from VX's trust-hint.js mechanic 9/6/26 [Mike: "copy
   functionality for the scroll hero bar scroll past action... it should say Click Here
   for License Info"]. Same source as VX's FDA-badge hint (people don't know the OCM
   badge is clickable until they scroll past it a few times). Driven by
   assets/js/trust-hint.js, which adds/removes .gg-cred--hint on scroll-into-view --
   re-arms on every scroll past the badge for the whole visit (gated by a random
   per-crossing chance plus a cooldown so it can't stack), retired permanently on first
   real interaction (click/focus). Pure CSS animation here -- the script only ever
   toggles one class. */
.gg-cred--hasinfo.gg-cred--hint { animation: gg-cred-pulse 1.6s ease-in-out 2; }
.gg-cred--hasinfo.gg-cred--hint::before {
	content: "Click Here for License Info";
	position: absolute;
	bottom: calc(100% + 10px);
	left: 50%;
	transform: translate(-50%, 4px);
	white-space: nowrap;
	background: var(--wp--preset--color--charcoal);
	color: var(--wp--preset--color--cream);
	font-size: var(--wp--preset--font-size--caption);
	font-weight: 600;
	padding: 0.35rem 0.7rem;
	border-radius: var(--wp--custom--radius--small);
	box-shadow: 0 6px 16px rgba(0,0,0,0.25);
	opacity: 0;
	animation: gg-cred-hint-fade 3.5s ease-in-out forwards;
	pointer-events: none;
	z-index: 61;
}
.gg-cred--hasinfo.gg-cred--hint::after {
	content: "";
	position: absolute;
	bottom: calc(100% + 4px);
	left: 50%;
	transform: translateX(-50%);
	border: 6px solid transparent;
	border-top-color: var(--wp--preset--color--charcoal);
	opacity: 0;
	animation: gg-cred-hint-fade 3.5s ease-in-out forwards;
	pointer-events: none;
	z-index: 61;
}
@keyframes gg-cred-pulse {
	0%, 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0); }
	50% { box-shadow: 0 0 0 8px rgba(0,0,0,0.18); }
}
@keyframes gg-cred-hint-fade {
	0% { opacity: 0; transform: translate(-50%, 4px); }
	15% { opacity: 1; transform: translate(-50%, 0); }
	80% { opacity: 1; transform: translate(-50%, 0); }
	100% { opacity: 0; transform: translate(-50%, -4px); }
}
@media (prefers-reduced-motion: reduce) {
	.gg-cred--hasinfo.gg-cred--hint,
	.gg-cred--hasinfo.gg-cred--hint::before,
	.gg-cred--hasinfo.gg-cred--hint::after { animation: none; }
}

/* ============================================================================
   FOUNDER / TEAM CARDS -- Meet the Team section.
   ============================================================================ */
/* 4 partners, not 5 (Mike, 8/31/26 -- Daniel Johnston dropped from this section). Real
   headshots now, mixed source aspect ratios (portrait, square) -- object-fit:cover on a
   fixed 1:1 box crops them to a consistent grid rather than distorting or letterboxing. */
.gg-team { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--wp--preset--spacing--small); margin-top: var(--wp--preset--spacing--medium); }
.gg-founder { text-align: center; }
/* object-position biased toward the top -- source headshots are tall portraits (up to
   1707x2560) forced into a 1:1 box; default center-crop clipped the top of the head on
   the tallest ones (Mike, 8/31/26). */
.gg-founder__photo {
  aspect-ratio: 1; width: 100%; object-fit: cover; object-position: center 12%; display: block;
  border-radius: var(--wp--custom--radius--large);
  margin-bottom: var(--wp--preset--spacing--small);
}
/* cream, not charcoal -- this section (.gg-section.is-dark) has a dark green background
   and inherited textColor:cream; the name was set to dark charcoal text regardless,
   nearly invisible against green-darker. Caught while wiring in real photos. */
.gg-founder__name { display: block; font-size: var(--wp--preset--font-size--base); font-weight: 700; color: var(--wp--preset--color--cream); }
.gg-founder__title { display: block; font-size: var(--wp--preset--font-size--caption); color: var(--wp--preset--color--green-vivid); margin-top: 0.15rem; }
@media (max-width: 700px) { .gg-team { grid-template-columns: repeat(2, 1fr); } }

/* Light-background variant, ADDED 9/6/26 -- inv-leadership.php reuses this exact grid
   (same 4 real headshots already on the homepage/Company Profile) on a light/cream
   section, unlike Meet the Team's dark one. The base rules above hardcode cream/
   green-vivid text for the dark case; this overrides both for legibility on cream,
   matching the same light/dark pairing used everywhere else (eyebrows, italic emphasis). */
.gg-section.is-light .gg-founder__name { color: var(--wp--preset--color--charcoal); }
.gg-section.is-light .gg-founder__title { color: var(--wp--preset--color--green-deep); }

/* ============================================================================
   LEADERSHIP BIO CARDS -- Company Profile page's "Our Team" anchor (ab-leadership.php).
   Richer than .gg-team/.gg-founder above (that's the homepage's simple name+title grid):
   same photo treatment, plus a full bio paragraph per person.
   ============================================================================ */
.gg-leaders { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--wp--preset--spacing--medium); margin-top: var(--wp--preset--spacing--medium); }
.gg-leader__photo {
  aspect-ratio: 1; width: 100%; object-fit: cover; object-position: center 12%; display: block;
  border-radius: var(--wp--custom--radius--large);
  margin-bottom: var(--wp--preset--spacing--small);
}
.gg-leader__name { font-size: var(--wp--preset--font-size--base); font-weight: 700; color: var(--wp--preset--color--cream); margin: 0; }
.gg-leader__title { font-size: var(--wp--preset--font-size--caption); color: var(--wp--preset--color--green-vivid); margin: 0.15rem 0 0.6rem; }
.gg-leader__bio { font-size: var(--wp--preset--font-size--small); line-height: 1.5; color: var(--wp--preset--color--cream); opacity: 0.85; margin: 0; }
@media (max-width: 900px) { .gg-leaders { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 500px) { .gg-leaders { grid-template-columns: 1fr; } }

/* .gg-nav .wp-block-navigation-item__content and .gg-header-ctas rules formerly lived
   here for core's wp:navigation block -- removed 8/31/26 when that block was replaced
   entirely by the custom mega-nav system (patterns/site-nav.php). See the big NAVIGATION
   CSS block earlier in this file for the new .gg-nav__* rules. */

/* ============================================================================
   FOOTER -- rebuilt 9/4/26 from VX's parts/footer.html structure (Mike: "look at the
   Vitamix Labs footer... so much better"). Column titles ported from VX's
   .vx-footer__col-title (small tracked uppercase h2s -- see that file's own comment on
   why h2, not h6, for the outline). GG's version adds the green-vivid accent color
   already established elsewhere (.gg-mega__coltitle) instead of VX's plain base color.
   ============================================================================ */
.gg-footer__col-title {
  font-size: var(--wp--preset--font-size--small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  line-height: 1.3;
  margin: 0 0 0.75rem;
}
footer .wp-block-list { margin: 0; padding: 0; }
footer .wp-block-list li { margin: 0; padding-block: 0.3rem; }

/* ============================================================================
   BUILD A PRODUCT CONFIGURATOR -- built 9/5/26 from "Build a Product — Configurator Spec"
   (Notion, LOCKED for Pre-Roll). Vanilla JS step wizard, no framework -- each step is a
   real DOM section toggled via a `.is-active` class, so no-JS still renders content (just
   not steppable), and the step order/skip logic lives in build-a-product.js, not baked into
   markup order. Reuses .gg-btn / .gg-section / --wp--preset tokens rather than inventing a
   parallel design system, since this is a core-site page, not a High-5's-style exception.
   ============================================================================ */
.gg-config { max-width: 780px; margin: 0 auto; }
.gg-config__progress {
  display: flex;
  gap: 0.4rem;
  margin-bottom: clamp(2rem, 5vw, 3rem);
  list-style: none;
  padding: 0;
}
.gg-config__progress li {
  flex: 1 1 0;
  height: 4px;
  border-radius: 2px;
  background: var(--wp--preset--color--hairline, rgba(31,36,33,0.12));
  transition: background-color 200ms ease;
}
.gg-config__progress li.is-done,
.gg-config__progress li.is-current { background: var(--wp--preset--color--green-vivid); }
.gg-config__steplabel {
  font-family: var(--gg-font-mono, inherit);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--charcoal-soft, #4a4f4b);
  margin: 0 0 0.5rem;
}
.gg-config__step { display: none; }
.gg-config__step.is-active { display: block; animation: gg-config-in 220ms ease; }
@keyframes gg-config-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.gg-config__title { margin: 0 0 0.5rem; }
.gg-config__hint { color: var(--wp--preset--color--charcoal-soft, #4a4f4b); margin: 0 0 1.5rem; font-size: var(--wp--preset--font-size--medium); }
.gg-config__field { margin-bottom: 1.5rem; }
.gg-config__field > label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.5rem;
}
.gg-config__label { font-weight: 600; margin: 0 0 0.75rem; }
.gg-config__field input[type="text"],
.gg-config__field input[type="number"],
.gg-config__field input[type="email"],
.gg-config__field input[type="tel"],
.gg-config__field textarea {
  width: 100%;
  padding: 0.75rem 1rem;
  border: 1.5px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.2));
  border-radius: 8px;
  font-size: var(--wp--preset--font-size--medium);
  font-family: inherit;
  background: #fff;
  box-sizing: border-box;
}
.gg-config__field input:focus,
.gg-config__field textarea:focus {
  outline: none;
  border-color: var(--wp--preset--color--green-vivid);
}
.gg-config__row { display: flex; gap: 1rem; flex-wrap: wrap; }
.gg-config__row .gg-config__field { flex: 1 1 220px; }
.gg-config__options {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}
.gg-config__option {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  border: 1.5px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.2));
  border-radius: 10px;
  padding: 1rem 1.1rem;
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
  background: #fff;
}
.gg-config__option:hover { border-color: var(--wp--preset--color--green-vivid); }

/* ⚠️ THE CONTROL IS VISIBLE NOW, 9/15/26 [Mike: "just needs to have a checkbox on each one
   that shows you selected it"]. It was opacity:0 with pointer-events:none, leaving a border
   tint as the only cue that anything had been chosen -- which reads as a button you pressed,
   not as one of several boxes you can tick. Showing the real control also makes the radio /
   checkbox distinction self-evident: a circle means pick one, a square means pick as many as
   you like, and nobody has to be told which this is. */
.gg-config__option input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.1rem 0 0;
  accent-color: var(--wp--preset--color--green-deep);
}

/* The step-2 boxes carry full service names ("Infused & Coated Pre-Roll Manufacturing"),
   which shred into four lines at the narrow column width the matrix grids use. */
.gg-config__step[data-step="products"] .gg-config__options {
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.gg-config__option.is-selected {
  border-color: var(--wp--preset--color--green-vivid);
  background: color-mix(in srgb, var(--wp--preset--color--green-vivid) 12%, white);
}
/* ⚠️ overflow-wrap IS LOAD-BEARING HERE, 9/15/26 [Mike: "Mixed Light/Greenhouse spills out
   of container"]. "Mixed-Light/Greenhouse" is one unbroken token as far as the line breaker
   is concerned -- a slash offers no break opportunity -- so at the grid's column width it ran
   straight out through the card's right edge. `anywhere` lets it break mid-token instead, and
   covers any future option long enough to do the same. */
.gg-config__option-title { font-weight: 700; display: block; overflow-wrap: anywhere; min-width: 0; }

/* The terpene follow-up: material on the left, the three choices wrapping on the right. */
.gg-config__terp-choices { display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; }
.gg-config__terp-choices label { display: inline-flex; align-items: center; gap: 0.35rem; white-space: nowrap; }
.gg-config__terps:empty { display: none; }
.gg-config__option-sub { font-size: var(--wp--preset--font-size--small); color: var(--wp--preset--color--charcoal-soft, #4a4f4b); display: block; margin-top: 0.2rem; }
.gg-config__help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--wp--preset--color--hairline, rgba(31,36,33,0.15));
  color: var(--wp--preset--color--charcoal-soft, #4a4f4b);
  font-size: 12px;
  font-weight: 700;
  margin-left: 0.4rem;
  cursor: help;
  position: relative;
  vertical-align: middle;
}
.gg-config__help .gg-config__tooltip {
  display: none;
  position: absolute;
  bottom: 130%;
  left: 50%;
  transform: translateX(-50%);
  width: 260px;
  background: var(--wp--preset--color--charcoal);
  color: var(--wp--preset--color--cream);
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 400;
  line-height: 1.4;
  z-index: 5;
  text-align: left;
  cursor: auto;
}
.gg-config__help:hover .gg-config__tooltip,
.gg-config__help:focus .gg-config__tooltip { display: block; }
/* ⚠️ SWITCHED FROM .is-visible TO THE [hidden] ATTRIBUTE, 9/15/26. The 4-step rebuild shows
   and hides these with `el.hidden`, which is the plainer mechanism -- but a class carrying
   `display: none` by default would beat it, and a class carrying `display: block` would beat
   the UA's own [hidden] rule. So the visible state is now the default and [hidden] is spelled
   out. The terp row needs its own [hidden] rule for the same reason: it is display:flex,
   which likewise outranks the UA default. */
.gg-config__subfield { margin: 0.75rem 0 1.5rem 0; padding: 1rem; border-radius: 8px; background: var(--wp--preset--color--cream); }
.gg-config__subfield[hidden] { display: none; }
.gg-config__toggle { display: flex; align-items: center; gap: 0.6rem; cursor: pointer; font-weight: 600; margin-bottom: 0.5rem; }
.gg-config__toggle input { width: 18px; height: 18px; }
.gg-config__terp-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; padding: 0.6rem 0; border-bottom: 1px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.12)); }
.gg-config__terp-row[hidden] { display: none; }
.gg-config__terp-row:last-child { border-bottom: none; }
.gg-config__unit-toggle { display: inline-flex; border: 1.5px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.2)); border-radius: 8px; overflow: hidden; }
.gg-config__unit-toggle button { border: none; background: #fff; padding: 0.6rem 1rem; font-size: var(--wp--preset--font-size--small); cursor: pointer; font-family: inherit; }
.gg-config__unit-toggle button.is-active { background: var(--wp--preset--color--green-vivid); }
.gg-config__nav { display: flex; justify-content: space-between; align-items: center; margin-top: clamp(2rem, 5vw, 3rem); gap: 1rem; }
.gg-config__nav-spacer { flex: 1; }
.gg-config__summary-card { border: 1.5px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.15)); border-radius: 12px; padding: clamp(1.25rem, 3vw, 2rem); margin-bottom: 1.5rem; }
.gg-config__summary-group { margin-bottom: 1.25rem; }
.gg-config__summary-group:last-child { margin-bottom: 0; }
.gg-config__summary-label { text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--wp--preset--font-size--small); color: var(--wp--preset--color--charcoal-soft, #4a4f4b); margin: 0 0 0.3rem; }
.gg-config__summary-value { margin: 0; font-weight: 600; }
.gg-config__review-check { display: flex; align-items: flex-start; gap: 0.75rem; padding: 1rem; border-radius: 8px; background: var(--wp--preset--color--cream); margin-bottom: 1.5rem; }
.gg-config__review-check input { width: 20px; height: 20px; margin-top: 0.1rem; flex: 0 0 auto; }
.gg-btn[disabled] .wp-block-button__link,
button.gg-btn:disabled {
  opacity: 0.45;
  pointer-events: none;
  cursor: not-allowed;
}
.gg-config__error.gg-config__options { outline: 2px solid #c0392b; outline-offset: 6px; border-radius: 10px; }
.gg-config__error.gg-config__field input { border-color: #c0392b; }
@media (max-width: 640px) {
  .gg-config__options { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
  .gg-config__nav { flex-wrap: wrap; }
}

/* ============================================================================
   REQUEST QUOTE -- built 9/5/26, REBUILT 9/15/26 [Mike: "The whole request a quote looks
   terrible tbh. Can you see the vitamix labs new site quote form? That's awesome,
   background looks great... says required next to important fields."].

   Ported from VX's assets/css/quote-form.css -- numbered sections as tinted boxes with a
   badge overlapping the corner, one tint across every section, 16px type, generous field
   padding. VX themes Fluent Forms' markup to get there; this is hand-rolled markup, so the
   class names are ours and the tokens are GG's (green-deep where VX used navy).

   ⚠️ EVERY SECTION CARRIES THE SAME TINT, and that is the VX rule worth repeating: a form
   reads as one object because its sections are structurally identical (label, control,
   repeat). Alternating tint/white -- correct everywhere else on this site -- makes a form
   look broken. Do not "fix" it back to alternating.

   Still reuses .gg-config__field / .gg-config__row / .gg-btn rather than forking a parallel
   form style, since those rules aren't scoped to a .gg-config ancestor.
   ============================================================================ */

/* 5% green-deep over white. Light enough to sit under white inputs without the inputs
   reading as a separate card, dark enough to bound the section. */
.rq-form,
.gg-config { --rq-tint: #F3F6F2; --rq-error: #c0392b; }

/* ============================================================================
   BUILD A PRODUCT -- the 4-step rebuild, 9/15/26 [Mike: "9 steps is unreal"].
   Deliberately borrows the quote form's tinted-card treatment: the two forms are the same
   act from a visitor's side, so they should not look like two different products.
   ============================================================================ */

/* Appears on the first tick of step 2 [Mike: "When they click on one, it should tell them
   that they will be entering more information in Step 3"]. */
.gg-config__notice {
  margin: var(--wp--preset--spacing--small) 0 0;
  padding: 0.85rem 1.1rem;
  border-left: 3px solid var(--wp--preset--color--green-deep);
  border-radius: var(--wp--custom--radius--subtle);
  background: var(--rq-tint);
  font-size: var(--wp--preset--font-size--base);
}

/* One card per thing checked on step 2. */
.gg-item {
  background: var(--rq-tint);
  border-radius: var(--wp--custom--radius--large);
  padding: var(--wp--preset--spacing--base);
  margin-bottom: var(--wp--preset--spacing--medium);
}
.gg-item[hidden] { display: none; }

.gg-item__title {
  margin: 0 0 var(--wp--preset--spacing--small);
  font-size: var(--wp--preset--font-size--large);
  font-weight: 700;
  color: var(--wp--preset--color--green-darker);
}

/* ⚠️ The pre-roll matrix sits inside a <details> [Mike: "That detailed matrix can be part of
   if they select pre-roll"]. It ships OPEN -- someone who checked a pre-roll asked for this,
   so hiding it behind a click would bury the thing they came for. The disclosure exists to
   let them collapse a long block once they have filled it, and to make the card's own
   boundary legible when several are open at once. */
.gg-item__spec {
  margin-top: var(--wp--preset--spacing--small);
  border-top: 1px solid var(--wp--preset--color--hairline);
  padding-top: var(--wp--preset--spacing--small);
}
.gg-item__spec > summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--wp--preset--color--green-deep);
  list-style: none;
}
.gg-item__spec > summary::-webkit-details-marker { display: none; }
.gg-item__spec > summary::before { content: "▾ "; display: inline-block; transition: transform 150ms ease; }
.gg-item__spec:not([open]) > summary::before { content: "▸ "; }
.gg-item__specbody { padding-top: var(--wp--preset--spacing--small); }

/* Inside a tinted card the option cards need a solid ground of their own to read against. */
.gg-item .gg-config__option { background: var(--wp--preset--color--cream); }

@media (max-width: 640px) {
  .gg-item { padding: var(--wp--preset--spacing--small); }
}

.rq-spec-summary { margin-bottom: 2rem; }
.rq-spec-note {
  margin: 0.6rem 0 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--charcoal-soft);
}
.rq-confirmation { text-align: center; padding: clamp(2rem, 5vw, 3rem) 1rem; }

/* ⚠️ position: relative is load-bearing -- the badge positions against it. */
.rq-section {
  position: relative;
  background: var(--rq-tint);
  border-radius: var(--wp--custom--radius--large);
  padding: var(--wp--preset--spacing--base);
  margin-bottom: var(--wp--preset--spacing--medium);
}

/* Negative offsets put the badge over the corner rather than inside the tint. */
.rq-section__badge {
  position: absolute;
  top: -0.9rem;
  left: -0.9rem;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  background: var(--wp--preset--color--green-deep);
  color: var(--wp--preset--color--cream);
  font-size: var(--wp--preset--font-size--base);
  font-weight: 700;
  box-shadow: 0 4px 10px rgba(31, 36, 33, 0.25);
}

/* ⚠️ Sized well above a field label on purpose -- VX's original miss was section headers
   reading at nearly the same size as the labels under them, so nothing established a
   hierarchy. */
.rq-section__title {
  margin: 0 0 var(--wp--preset--spacing--small);
  font-size: var(--wp--preset--font-size--xlarge);
  font-weight: 700;
  color: var(--wp--preset--color--green-darker);
}

.rq-form .gg-config__field > label,
.rq-form .rq-fieldset legend {
  display: block;
  margin-bottom: 0.4rem;
  font-weight: 600;
  font-size: var(--wp--preset--font-size--base);
  color: var(--wp--preset--color--charcoal);
}

.rq-fieldset { border: none; padding: 0; margin: 0 0 1.5rem; }

/* ⚠️ AN ASTERISK, NOT THE WORD, 9/15/26 [Mike: "you dont need to write the whole word
   required everywhere"]. This started as a full REQUIRED chip beside every required label,
   which read as clutter once four of them stacked up. The single legend under the form
   decodes the mark once, which is all it needs. */
.rq-req {
  margin-left: 0.15rem;
  color: var(--wp--preset--color--green-deep);
  font-weight: 700;
}
.rq-optional {
  margin-left: 0.4rem;
  color: var(--wp--preset--color--charcoal-soft);
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 400;
}
.rq-required-note {
  margin: 0 0 var(--wp--preset--spacing--small);
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--charcoal-soft);
}

.rq-form .gg-config__field select {
  width: 100%;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--wp--preset--color--hairline);
  border-radius: var(--wp--custom--radius--base);
  background: var(--wp--preset--color--cream);
  color: var(--wp--preset--color--charcoal);
  font-family: inherit;
  font-size: var(--wp--preset--font-size--base);
}
.rq-form .gg-config__field select:focus {
  outline: none;
  border-color: var(--wp--preset--color--green-deep);
  box-shadow: 0 0 0 3px rgba(63, 95, 58, 0.18);
}

/* Radio pills -- short answers inline instead of a stacked list. */
.rq-pills { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.rq-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--wp--preset--color--hairline);
  border-radius: 999px;
  background: var(--wp--preset--color--cream);
  font-size: var(--wp--preset--font-size--base);
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.rq-pill input { accent-color: var(--wp--preset--color--green-deep); margin: 0; }
.rq-pill:hover { border-color: var(--wp--preset--color--green-deep); }
.rq-pill.is-selected {
  border-color: var(--wp--preset--color--green-deep);
  background: rgba(63, 95, 58, 0.1);
  font-weight: 600;
}

.rq-conditional { margin-top: var(--wp--preset--spacing--small); }

/* ⚠️ The honeypot. Moved off-screen rather than display:none -- some bots skip anything
   that is display:none or [hidden], which defeats the point of having one. */
.rq-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ⚠️ NOT FULL-WIDTH, 9/15/26 [Mike: "that button needs to be the correct stylization and
   feel of the rest of the site"]. VX's submit spans the form and that is fine there, but
   every other button on THIS site is an inline auto-width pill -- a full-bleed bar reads as
   a different component. Inherits .gg-btn.is-primary wholesale now; no size override. */
.rq-submit { margin-top: var(--wp--preset--spacing--small); }

/* Red appears nowhere else on this site except an error, deliberately -- it is the one
   moment the colour is the expected one. */
.rq-alert {
  margin-bottom: var(--wp--preset--spacing--small);
  padding: 0.85rem 1.1rem;
  border-left: 3px solid var(--rq-error);
  border-radius: var(--wp--custom--radius--subtle);
  background: rgba(192, 57, 43, 0.08);
  color: var(--rq-error);
  font-size: var(--wp--preset--font-size--base);
}

@media (max-width: 640px) {
  .rq-section { padding: var(--wp--preset--spacing--small); }
  .rq-section__badge { top: -0.75rem; left: -0.5rem; width: 2rem; height: 2rem; }
  .rq-pills { flex-direction: column; align-items: stretch; }
}

/* ============================================================================
   INVESTORS -- market-growth data visualization, ADDED 9/6/26 [Mike: "create a real graph
   to put in the industry growth section"]. Sits below "The New York Cannabis Opportunity"
   copy (inv-opportunity-traction.php) -- a real chart, not a stock photo, since this
   section's own docblock already reasoned market data isn't something a photo can show.
   Every number here is one already stated in that section's own copy -- nothing invented.
   The dispensary comparison intentionally omits a specific "2 years ago" figure (the source
   only says "more than double the count from two years earlier", no exact prior number) --
   its bar is drawn at a fixed ~45% of the "Today" bar's height as an illustrative
   less-than-half proportion, not a plotted data point.
   ============================================================================ */
.gg-stat-chart {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 4vw, 2.5rem);
  margin-top: clamp(2rem, 4vw, 2.5rem);
}
.gg-stat-chart__item { display: flex; flex-direction: column; align-items: flex-start; }
.gg-stat-chart__bars {
  display: flex;
  align-items: flex-end;
  gap: 0.6rem;
  height: 110px;
  width: 100%;
  margin-bottom: 1rem;
}
.gg-stat-chart__bar {
  flex: 1;
  height: 45%;
  border-radius: 4px 4px 0 0;
  background: var(--wp--preset--color--green-deep);
  opacity: 0.35;
  position: relative;
}
.gg-stat-chart__bar--current { height: 100%; opacity: 1; }
.gg-stat-chart__bar-label {
  position: absolute;
  bottom: -1.5rem;
  left: 0;
  right: 0;
  text-align: center;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--charcoal-soft, #4a4f4b);
  white-space: nowrap;
}
.gg-stat-chart__track {
  width: 100%;
  height: 10px;
  border-radius: 5px;
  background: rgba(31, 36, 33, 0.1);
  margin-bottom: 1rem;
  overflow: hidden;
}
.gg-stat-chart__fill { height: 100%; border-radius: 5px; background: var(--wp--preset--color--green-deep); }
.gg-stat-chart__figure {
  font-family: var(--wp--preset--font-family--display, inherit);
  font-size: clamp(1.75rem, 3.5vw, 2.25rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 0.35rem;
  color: var(--wp--preset--color--charcoal);
}
.gg-stat-chart__caption { margin: 0; font-size: var(--wp--preset--font-size--small); color: var(--wp--preset--color--charcoal-soft, #4a4f4b); }
@media (max-width: 700px) {
  .gg-stat-chart { grid-template-columns: 1fr; gap: 2.5rem; }
  .gg-stat-chart__bars { margin-bottom: 2rem; }
}

/* ============================================================================
   NEWS + RESOURCES -- built 9/6/26 [Mike: "copy same layout as Vitamix Labs for
   News... make Resources the same general layout... same general layout with tags
   and categories works for both"]. Ported the Vitamix Labs (VX) mosaic-tile mechanic:
   image-bled dark-scrim cards, first post gets a 2x2 feature tile, category/tag chips
   as display badges (no filter UI). Named gg-blog-* rather than reusing this theme's
   own .gg-tile/.gg-mosaic (that's the homepage Services mosaic -- a different, light
   product-card layout, not this one) -- see news-grid.php's docblock.
   ============================================================================ */
.gg-blog-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* ⚠️ 300px -> 360px -> 380px 9/7/26: every tile now carries an excerpt (see
     news-grid.php's docblock, Mike preferred it over title-only cards), not just the
     feature tile -- 300px was sized for a title-only card and overflowed once every tile
     grew a second block of text. Bumped again to 380px once excerpts were locked to a
     consistent 4 visible lines (line-clamp, see .gg-blog-tile__excerpt) instead of a
     shorter word-count trim that had only needed 3. */
  grid-auto-rows: 380px;
  gap: var(--wp--preset--spacing--small);
  margin-top: var(--wp--preset--spacing--medium);
}
.gg-blog-tile {
  position: relative;
  display: block;
  min-height: 380px;
  overflow: hidden;
  border-radius: var(--wp--custom--radius--large);
  text-decoration: none;
  isolation: isolate;
  background: var(--wp--preset--color--green-darker);
}
.gg-blog-tile--feature { grid-column: span 2; grid-row: span 2; }
.gg-blog-tile__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -2;
  transition: transform 500ms cubic-bezier(0.2, 0, 0.2, 1);
}
.gg-blog-tile:hover .gg-blog-tile__img { transform: scale(1.04); }
.gg-blog-tile::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(26, 46, 31, 0) 0%, rgba(26, 46, 31, 0.12) 40%, rgba(26, 46, 31, 0.6) 68%, rgba(26, 46, 31, 0.9) 100%);
}
.gg-blog-tile__tags {
  position: absolute;
  top: 0.875rem;
  left: 0.875rem;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  max-width: calc(100% - 1.75rem);
}
.gg-blog-tile__tag {
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.35rem 0.55rem;
  border-radius: var(--wp--custom--radius--subtle);
  background: var(--wp--preset--color--green-vivid);
  color: var(--wp--preset--color--charcoal);
  white-space: nowrap;
}
.gg-blog-tile__tag--topic {
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: var(--wp--preset--color--cream);
  font-weight: 500;
}
.gg-blog-tile__badge {
  position: absolute;
  top: 0.875rem;
  right: 0.875rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.35rem 0.6rem;
  border-radius: var(--wp--custom--radius--subtle);
  background: rgba(248, 246, 241, 0.92);
  color: var(--wp--preset--color--green-darker);
}
.gg-blog-tile__body {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: var(--wp--preset--spacing--small);
  z-index: 2;
}
.gg-blog-tile__meta { font-size: var(--wp--preset--font-size--caption); color: rgba(248, 246, 241, 0.72); }
.gg-blog-tile__title {
  font-family: var(--wp--preset--font-family--display);
  color: var(--wp--preset--color--cream);
  font-size: var(--wp--preset--font-size--xlarge);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.gg-blog-tile--feature .gg-blog-tile__title { font-size: var(--wp--preset--font-size--heading); }
/* ⚠️ FIXED 9/7/26 [Mike: "needs to also show same amount of text on each excerpt... I
   like the 4 lines more than the 3"] -- two rounds. Round 1 added line-clamp:4, which
   caps the MAXIMUM lines but doesn't force 4 -- a wide tile still wraps the same text to
   FEWER lines just because it has more room per line (confirmed live: the wide 2x2
   feature tile wrapped to 3 lines while the narrow plain tile wrapped the same 40-word
   trim to 4). Actual fix is this max-width: 280px -- capping the excerpt's own column to
   roughly the plain tile's width forces near-identical characters-per-line regardless of
   how wide the tile itself is, so both land on 4 lines for text of comparable length,
   which is what line-clamp:4 is then there to guarantee as an upper bound. */
.gg-blog-tile__excerpt {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
  max-width: 280px;
  margin-top: 0.25rem;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.45;
  color: rgba(248, 246, 241, 0.88);
}
.gg-blog-empty { padding: var(--wp--preset--spacing--large) 0; color: var(--wp--preset--color--charcoal-soft, #4a4f4b); }
@media (max-width: 1024px) { .gg-blog-grid { grid-template-columns: repeat(2, 1fr); } }
/* ⚠️ FIXED 9/7/26 [Mike: feature tile on mobile, title text overlapping the category
   chip]: .gg-blog-tile__tags and .gg-blog-tile__body are both position:absolute inside
   the tile, so neither contributes to the tile's own height -- the tile is exactly
   min-height tall no matter how much text is in its body. The feature tile's longer
   title + excerpt needed more room than the flat 240px every tile shared; on a long
   title that overflowed upward past the tile's visible box and collided with the tags
   pinned to the top.
   ⚠️ 240px -> 320px -> 340px 9/7/26: every plain tile now carries an excerpt too (Mike
   preferred it over title-only, see news-grid.php's docblock), so the plain-tile floor
   needed raising the same way the feature tile's did above -- same root cause, same fix.
   Bumped again to 340px once excerpts locked to a consistent 4 lines (line-clamp) instead
   of a shorter 3-line word-count trim. */
@media (max-width: 600px) {
  .gg-blog-grid { grid-template-columns: 1fr; grid-auto-rows: auto; }
  .gg-blog-tile { grid-column: span 1; grid-row: span 1; min-height: 340px; }
  .gg-blog-tile--feature { min-height: 480px; }
  .gg-blog-tile--feature .gg-blog-tile__title { font-size: var(--wp--preset--font-size--xlarge); }
}

/* Article header (single gg_news / gg_resource) -- date + category/tag chips under the
   H1, on the light hero, then the featured image full-bleed below. */
.gg-article__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-top: 1rem; }
.gg-article__date { font-size: var(--wp--preset--font-size--small); color: var(--wp--preset--color--charcoal-soft, #4a4f4b); }
.gg-article__chip {
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.3rem 0.6rem;
  border-radius: var(--wp--custom--radius--subtle);
  background: var(--wp--preset--color--green-deep);
  color: var(--wp--preset--color--cream);
  text-decoration: none;
}
.gg-article__chip--topic {
  background: transparent;
  border: 1px solid var(--wp--preset--color--hairline);
  color: var(--wp--preset--color--charcoal-soft, #4a4f4b);
  font-weight: 500;
}
.gg-article__figure { margin: var(--wp--preset--spacing--medium) 0 0; }
.gg-article__figure img { width: 100%; height: auto; display: block; max-height: 520px; object-fit: cover; }
.gg-eyebrow--withbadge { display: flex; align-items: center; gap: 0.6rem; }
.gg-article__badge {
  display: inline-flex;
  align-items: center;
  font-size: var(--wp--preset--font-size--caption);
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: var(--wp--custom--radius--subtle);
  background: var(--wp--preset--color--green-deep);
  color: var(--wp--preset--color--cream);
}
/* wp:post-content article body -- readable measure, real spacing between elements
   (core's post-content block ships with none of its own). */
.gg-art__body :where(h2, h3) { margin-top: 2em; }
.gg-art__body :where(p, ul, ol) { max-width: 720px; }
.gg-art__body ul, .gg-art__body ol { padding-left: 1.25rem; }

/* ============================================================================
   AGE GATE -- sitewide (Mike, 10/4/26). Markup in inc/age-gate.php, behavior in
   assets/js/age-gate.js. An inline <head> script adds .gg-age-locked to <html> before first
   paint when the gg_age_ok cookie is missing; CSS is the only thing that shows the overlay,
   so it is safe behind the CDN's long HTML cache. The backdrop is opaque on purpose -- a
   gate, not a hint. The card is pure white because the logo asset is a JPG on white.
   ============================================================================ */
.gg-agegate { display: none; }
html.gg-age-locked { overflow: hidden; }
html.gg-age-locked .gg-agegate {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 1000;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  overflow-y: auto;
  background:
    radial-gradient(60% 50% at 15% 10%, rgba(164,214,94,0.20), transparent 70%),
    radial-gradient(55% 45% at 90% 95%, rgba(63,95,58,0.55), transparent 70%),
    var(--wp--preset--color--green-darker, #1A2E1F);
  animation: gg-agegate-in 0.35s ease-out both;
}
@keyframes gg-agegate-in { from { opacity: 0; } to { opacity: 1; } }
.gg-agegate__card {
  position: relative;
  width: min(100%, 480px);
  margin: auto;
  padding: clamp(2rem, 6vw, 2.75rem) clamp(1.5rem, 6vw, 2.75rem) 1.5rem;
  background: #fff;
  color: var(--wp--preset--color--charcoal, #1F2421);
  border-radius: 20px;
  text-align: center;
  box-shadow: 0 0 0 1px rgba(255,255,255,0.08), 0 40px 90px -25px rgba(0,0,0,0.65);
  overflow: hidden;
}
.gg-agegate__card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 5px;
  background: linear-gradient(90deg, var(--wp--preset--color--green-deep, #3F5F3A), var(--wp--preset--color--green-vivid, #A4D65E));
}
.gg-agegate__logo { display: block; width: min(230px, 62%); height: auto; margin: 0 auto 1.5rem; }
.gg-agegate__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.9rem;
  padding: 0.3rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--wp--preset--color--green-darker, #1A2E1F);
  background: var(--wp--preset--color--green-vivid, #A4D65E);
  border-radius: 999px;
}
.gg-agegate__title {
  margin: 0 0 0.75rem;
  font-family: var(--wp--preset--font-family--display, Georgia, serif);
  font-size: clamp(1.9rem, 6vw, 2.4rem);
  line-height: 1.12;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.gg-agegate__title:focus { outline: none; }
.gg-agegate__text {
  margin: 0 auto 1.75rem;
  max-width: 38ch;
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--wp--preset--color--charcoal-soft, #4A4F4B);
}
.gg-agegate__actions { display: flex; flex-direction: column; gap: 0.7rem; }
.gg-agegate__btn {
  width: 100%;
  padding: 0.95rem 1.25rem;
  font: inherit;
  font-weight: 600;
  border-radius: 999px;
  cursor: pointer;
  border: 2px solid var(--wp--preset--color--green-deep, #3F5F3A);
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.gg-agegate__btn.is-yes { background: var(--wp--preset--color--green-deep, #3F5F3A); color: #fff; }
.gg-agegate__btn.is-yes:hover { background: var(--wp--preset--color--green-darker, #1A2E1F); border-color: var(--wp--preset--color--green-darker, #1A2E1F); transform: translateY(-1px); }
.gg-agegate__btn.is-no { border-color: var(--wp--preset--color--hairline, rgba(31,36,33,0.12)); background: transparent; color: var(--wp--preset--color--charcoal-soft, #4A4F4B); }
.gg-agegate__btn.is-no:hover { background: rgba(31,36,33,0.05); }
.gg-agegate__btn:focus-visible { outline: 3px solid var(--wp--preset--color--green-vivid, #A4D65E); outline-offset: 2px; }
.gg-agegate__fine {
  margin: 1.75rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--wp--preset--color--hairline, rgba(31,36,33,0.12));
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--wp--preset--color--charcoal-soft, #4A4F4B);
  opacity: 0.8;
}
@media (prefers-reduced-motion: reduce) {
  html.gg-age-locked .gg-agegate { animation: none; }
  .gg-agegate__btn { transition: none; }
}
