/* ===========================================================================
   GGIS × Divi — reconciliation

   WHILE ITERATING: paste this into Divi → Theme Options → General → Custom CSS.
   It applies instantly, with no theme re-upload. Once the layout looks right,
   it gets folded into the child theme's style.css for the final build.

   Everything here is scoped to sections that carry a ggis-* class, so the rest
   of the site behaves like normal Divi.

   VERIFIED against the live Divi 5 DOM (greengarden.kesatria.my): Divi 5 keeps
   the et_pb_section / et_pb_row / et_pb_column / et_pb_text class names, and
   ggis.css already lands correctly (tint band, hairlines, 56px section padding,
   Fraunces + Instrument Sans, colours). The ONE deviation from the approved
   design was the column gap — Divi's default gutter is ~99px where the design
   uses 48px. The grid rules below restore the design's exact grid.
=========================================================================== */

/* --- Divi default spacing (defensive; no-ops where Divi is already clean) --- */

/* Nested rows (Divi 5 Row-in-Column) manage their own padding — the section
   gutter + zeroing below is only for the top-level container rows.
   Do NOT add :not() exclusions here. Each one raises this rule from (0,4,0) to
   (0,5,0), which then outranks the (0,4,0) restorations further down the file -
   adding :not(.ggis-hero__content) silently stripped the footer grid/bar padding
   (5rem and 2rem) and left the footer flush against the CTA. Rows that need their
   padding back get an explicit rule LATER in this file instead, where equal
   specificity wins on order - see the hero content row and footer blocks. */
.et_pb_section[class*="ggis-"] .et_pb_row:not(.et_pb_row_nested) {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* Responsive side gutter — the design's .ggis-container padding-inline
   (24 / 40 / 64 / 96px). Divi rows have none, so below the 1800px frame the
   content ran flush to the screen edges. The hero already carries the gutter
   via its own .ggis-container, so it's excluded. Applies to every ggis section
   (and the footer) on every page. */
.et_pb_section[class*="ggis-"]:not(.ggis-hero) .et_pb_row:not(.et_pb_row_nested) {
  padding-left: 1.5rem !important;
  padding-right: 1.5rem !important;
}
@media (min-width: 48rem) {
  .et_pb_section[class*="ggis-"]:not(.ggis-hero) .et_pb_row:not(.et_pb_row_nested) {
    padding-left: 2.5rem !important;
    padding-right: 2.5rem !important;
  }
}
@media (min-width: 80rem) {
  .et_pb_section[class*="ggis-"]:not(.ggis-hero) .et_pb_row:not(.et_pb_row_nested) {
    padding-left: 4rem !important;
    padding-right: 4rem !important;
  }
}
@media (min-width: 96rem) {
  .et_pb_section[class*="ggis-"]:not(.ggis-hero) .et_pb_row:not(.et_pb_row_nested) {
    padding-left: 6rem !important;
    padding-right: 6rem !important;
  }
}

/* Divi forces a ~54px bottom margin on every module. It beats an unprefixed
   rule on specificity, so this needs !important — verified on the live Divi 5
   DOM. Zeroing it lets the GGIS classes own the vertical rhythm: the gaps
   between a stat's number, label and note come from ggis.css (12px, then 8px),
   not from Divi's module spacing. */
/* --- Divi's body typography overrides the design system ---------------------
   Divi core ships "body { line-height: 1.7em; font-weight: 500 }". Both beat
   ggis.css's own "body" rule on load order, and both are wrong here:
   - 1.7em COMPUTES to a fixed 28.9px and inherits as a length, so small type
     (.ggis-statcard__sub at 11px) could never tighten - it sat on a 29px line
     instead of 18px, inflating every stacked text block.
   - font-weight 500 rendered all body copy one step heavier than the design.
   Restated here at (0,1,1) so it wins regardless of enqueue order. Values are
   ggis.css's own.
   font-size is the third and worst of them: Divi emits
   `body{font-size:var(--et_global_body_font_size)}` (14px) in an inline block at
   the very END of the document - after this file - so it beat ggis.css on order.
   Everything that inherits its size rendered 14px instead of 17px, and every ch/em
   measure resolved ~18% narrow: the Regional Synergy statement capped at 68ch came
   out 634px instead of 770px, squeezing its heading from 2 lines to 3. */
body.et_divi_theme {
  font-size: var(--fs-body-lg);
  line-height: 1.65;
  font-weight: 400;
}

/* Divi also sets .et_pb_text { line-height: var(--et_global_body_font_height,
   1.7em) }, which re-introduces the same fixed 28.9px inside every Text module
   even once body is corrected. Restated unitless so each element computes its
   own leading from its own font-size, exactly as ggis.css intends. */
.et_pb_section[class*="ggis-"] .et_pb_text {
  line-height: 1.65;
}

.et_pb_section[class*="ggis-"] .et_pb_module {
  margin-bottom: 0 !important;
}

/* Divi puts padding-bottom:1em on EVERY <p>. The static build has none, so it is
   always wrong here - reset it on all paragraphs, classed or not. This used to
   exclude ggis-* paragraphs, which left 45.6px hanging under
   .ggis-statcard__figure and made every stat card ~83px too tall. */
:where(.et_pb_section[class*="ggis-"]) p {
  padding-bottom: 0;
}

/* Divi also ships `p:not(.has-background):last-of-type { padding-bottom: 0 }`,
   which sits at (0,2,1) - higher than ANY single-class design rule. Inside a Divi
   Text module almost every design paragraph is the only <p> and therefore
   :last-of-type, so that rule silently strips padding the design sets. It cost the
   hero eyebrow chip its lower half: 31px tall became 23px, with the label sitting
   on the floor of the pill. These are the only two paragraphs in ggis.css that
   carry padding (the About eyebrow chip is a <span>, so it is untouched), restated
   here above Divi's rule. */
.et_pb_section[class*="ggis-"] p.ggis-hero__eyebrow {
  padding-bottom: 0.5rem;
}
@media (min-width: 64rem) {
  .et_pb_section[class*="ggis-"] p.ggis-abouthero__intro {
    padding-bottom: 0.5rem;
  }
}

/* Same story for headings: Divi ships
   h1..h6 { color:#333; padding-bottom:10px; line-height:1em; font-weight:500 }.
   ggis.css already wins on colour, weight and leading, but the 10px padding
   leaked through and added a false gap under every heading (it made each
   .ggis-usp__title 10px taller than the design), #333 hijacked every heading
   that inherits its colour, and line-height:1em collapsed the leading on any
   heading without its own rule (.ggis-process-card__title rendered 28px tall
   instead of 46px).
   The :where() wrapper is deliberate: it holds this rule at (0,0,1) - the same
   specificity as Divi's own h1..h6 - so it wins purely on load order (this file
   is enqueued after the Divi theme CSS) while still LOSING to every .ggis-*
   heading rule. Headings that declare their own size/colour/leading keep it;
   the rest inherit from the section, exactly as the static build does. */
:where(.et_pb_section[class*="ggis-"]) :is(h1, h2, h3, h4, h5, h6) {
  padding-bottom: 0;
  color: inherit;
  line-height: inherit;
}

/* Margins are a different matter: ggis-* paragraphs (e.g. .ggis-synergy__cta,
   .ggis-card__text) carry intended margins from ggis.css, so only unclassed
   paragraphs get theirs zeroed. */
.et_pb_section[class*="ggis-"] .et_pb_text p:not([class*="ggis-"]) {
  margin: 0;
}

/* --- Restore the design's grids -------------------------------------------
   In the static build each multi-column band was a CSS grid with a specific
   gap (ggis.css). Divi lays the same columns out with its gutter system, whose
   default gap is wider. Re-assert the design grid on the Divi row so the gap
   and breakpoints match exactly. One block per section; add the rest as each
   section is imported.

   Trust strip — design: 1 col (mobile) / 2 col (>=768) / 4 col (>=1024), gap
   2.5rem then 3rem. */
.ggis-trust .et_pb_row {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}
.ggis-trust .et_pb_row > .et_pb_column {
  width: auto !important;
  margin: 0 !important;
  float: none !important;
}
@media (min-width: 768px) {
  .ggis-trust .et_pb_row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3rem;
  }
}
@media (min-width: 1024px) {
  .ggis-trust .et_pb_row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* General: any Divi row marked "ggis-grid" (via module_class) has Divi's column
   widths/margins/floats freed, so a CSS grid can lay the columns out. The grid
   template + gap for each such row is set per-section below. */
.et_pb_section[class*="ggis-"] .et_pb_row.ggis-grid > .et_pb_column {
  width: auto !important;
  margin: 0 !important;
  float: none !important;
  /* let fr tracks keep their share instead of a wide image expanding its own
     column past its allocation (the contact 60/40 was collapsing to ~38/62). */
  min-width: 0 !important;
}

/* USP — design: 1 col (mobile) / 3 col (>=768), gap 3rem then 2.5rem, with a
   4.5rem gap below the section heading. The vertical hairline between columns
   comes from ggis.css (.ggis-usp__col + .ggis-usp__col). */
.ggis-usp .et_pb_row.ggis-grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 3rem;
  margin-top: 4.5rem;
  align-items: start;
}
@media (min-width: 768px) {
  .ggis-usp .et_pb_row.ggis-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2.5rem;
  }
}

/* Services — 1 col (mobile) / 3 col (>=768); gap 4rem/2rem then 5rem/3rem.
   align-items:start so cards keep their 4:5 figures instead of stretching to
   match the tallest card (grid's default is stretch). */
.ggis-services .et_pb_row.ggis-grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 4rem 2rem;
  margin-top: 4.5rem;
  align-items: start;
}
@media (min-width: 768px) {
  .ggis-services .et_pb_row.ggis-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (min-width: 1280px) {
  .ggis-services .et_pb_row.ggis-grid {
    gap: 5rem 3rem;
  }
}

/* Regional synergy — the SG × MY map: 1 col (mobile) / 1fr-auto-1fr (>=1024),
   so the middle connector column stays narrow. */
.ggis-synergy .et_pb_row.ggis-grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  align-items: center;
  margin-top: 4rem;
}
@media (min-width: 1024px) {
  .ggis-synergy .et_pb_row.ggis-grid {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: 3rem;
  }
}

/* Contact — 60/40 at desktop. */
.ggis-cta .et_pb_row.ggis-grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 3.5rem;
  align-items: start;
}
@media (min-width: 1024px) {
  .ggis-cta .et_pb_row.ggis-grid {
    grid-template-columns: 60fr 40fr;
    gap: 5rem;
  }
}

/* --- Hero ------------------------------------------------------------------
   The hero sizes itself by content (min-height:100svh) with absolutely-
   positioned media behind, so Divi's default section padding must be zero or
   it adds bands above and below the full-height frame.
   Divi's et_flex_section also adds row-gap:var(--vertical-gap) (60px) between
   rows; the media row is a 0-height positioning shell rather than a layout
   sibling, so that gap pushed the copy down and made the section 60px taller
   than the 100svh frame. */
.ggis-hero.et_pb_section {
  padding: 0 !important;
  row-gap: 0 !important;
}

/* Divi's row/column/module wrappers are position:relative and collapse to zero
   height (their only child, the media, is absolute) — so the absolute media was
   filling a 0px box and the hero showed only the green background. Forcing the
   wrappers static makes the media's containing block the hero section itself,
   so it fills the full 100svh frame. Verified on the live Divi 5 DOM. */
.ggis-hero .ggis-hero__mediawrap,
.ggis-hero .ggis-hero__mediawrap .et_pb_column,
.ggis-hero .ggis-hero__mediawrap .et_pb_module,
.ggis-hero .ggis-hero__mediawrap .et_pb_text_inner,
.ggis-hero .ggis-hero__mediawrap .et_pb_code_inner {
  position: static !important;
  min-height: 0;
}

/* Scoped to the MEDIA row only. Two reasons it must not hit the content row:
   (1) v1.1 moved the media from a Text module into a Code module, so
       .et_pb_code_inner (position:relative in Divi core) joined the chain and
       has to be neutralised too, and
   (2) the content row needs to keep ggis.css's own position:relative,
       min-height:100svh and justify-content:flex-end — otherwise the copy
       collapses to its natural height at the TOP of the frame and the absolute
       media paints straight over it. */
.ggis-hero .et_pb_row.ggis-hero__content {
  position: relative !important;
  z-index: 1;
}

/* --- Divi Image module -> ggis figure --------------------------------------
   The figure (.ggis-figure) owns the size: width 100% of its column + the
   aspect-ratio from ggis.css (4/5 or 3/2). Divi's .et_pb_image_wrap is pulled
   absolute to fill that box, so the natural-size <img> can't overflow its
   column (services cards were spilling ~134px and overlapping) and the aspect
   ratio holds. */
.ggis-figure.et_pb_image {
  width: 100%;
  margin: 0;
}
.ggis-figure .et_pb_image_wrap {
  position: absolute;
  inset: 0;
  display: block;
}
.ggis-figure .et_pb_image_wrap img,
.ggis-figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --- Divi blockquote chrome ------------------------------------------------
   Divi gives every <blockquote> a blue accent left border + padding. The GGIS
   synergy quote is plain italic serif, so strip it. */
.et_pb_section[class*="ggis-"] blockquote {
  border: 0;
  padding-left: 0;
  margin-left: 0;
}

/* --- Contact form ----------------------------------------------------------
   Restyle Divi's Contact Form module (add class "ggis-form" to it) into the
   GGIS minimal look: transparent fields with hairline underlines, micro-caps
   labels, gold focus, and a pill submit button. Divi's own form styling is
   heavy and specific, so these need !important. */

/* ggis.css's .ggis-form is a 2-col grid meant for OUR form markup; on Divi's
   contact-form container (one child) it shoves the whole form into one grid
   cell (half width, right-aligned). Force block so Divi lays the fields out
   itself, full width. */
.et_pb_contact_form_container.ggis-form {
  display: block !important;
}
/* Divi auto-margins the submit container to the right; the design has it left,
   with a bit of breathing room above the button. */
.ggis-form .et_contact_bottom_container {
  margin-left: 0 !important;
  text-align: left !important;
  margin-top: 1.5rem !important;
}
/* Divi gives the submit button its own left margin — align it flush with the
   fields. Needs the extra ancestor to beat Divi's specificity. */
.ggis-form .et_contact_bottom_container .et_pb_contact_submit {
  margin: 0 !important;
}

/* Divi puts a 30px flex gap between a field's label and its input; the design
   uses the label's own 12px margin, so zero the flex gap. */
.ggis-form .et_pb_contact_field {
  padding: 0 !important;
  background: transparent !important;
  margin-bottom: 1.5rem !important;
  gap: 0 !important;
}
.ggis-form .et_pb_contact_form_label {
  display: block !important;
  font-family: var(--ggis-font-sans);
  font-size: var(--fs-micro);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(250, 247, 240, 0.6) !important;
  margin-bottom: 0.75rem;
}
.ggis-form .et_pb_contact_field input,
.ggis-form .et_pb_contact_field select,
.ggis-form .et_pb_contact_field textarea {
  width: 100% !important;
  padding: 0.85rem 0 !important;
  border: 0 !important;
  border-bottom: 1px solid rgba(250, 247, 240, 0.25) !important;
  border-radius: 0 !important;
  background: transparent !important;
  color: var(--ggis-canvas) !important;
  font-family: var(--ggis-font-sans) !important;
  font-size: var(--fs-body-lg) !important;
  box-shadow: none !important;
}
.ggis-form select {
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.ggis-form select option {
  color: var(--ggis-ink);
}
.ggis-form input::placeholder {
  color: rgba(250, 247, 240, 0.35);
}
.ggis-form input:focus,
.ggis-form select:focus,
.ggis-form textarea:focus {
  outline: none !important;
  border-bottom-color: var(--ggis-gold) !important;
}
.ggis-form .et_pb_contact_submit {
  background: var(--ggis-canvas) !important;
  color: var(--ggis-green-950) !important;
  border: 0 !important;
  border-radius: 999px !important;
  padding: 1rem 2rem !important;
  font-family: var(--ggis-font-sans) !important;
  font-size: var(--fs-meta) !important;
  font-weight: 500 !important;
  letter-spacing: 0.08em !important;
  text-transform: uppercase !important;
  transition: background-color 0.3s ease;
}
.ggis-form .et_pb_contact_submit:hover {
  background: var(--ggis-canvas-tint) !important;
}

/* --- Footer ghost wordmark -------------------------------------------------
   The oversized "GreenGarden" sits inside a Divi row capped at 1800px (plus the
   side gutter above), so on wide screens it centred on that box, not the
   viewport — visibly off-centre. Break it out to the full viewport width and
   centre it there. */
.ggis-footer .ggis-ghost {
  width: 100vw !important;
  max-width: none !important;
  position: relative !important;
  left: 50% !important;
  transform: translateX(-50%) !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  text-align: center !important;
}

/* ==========================================================================
   About page — native Divi 5 rewrite (2026-08).

   Sections import with a native Flex layout style; rows default to Flex in
   Divi 5 and ggis.css overrides them to the design's grids (.ggis-values__grid
   / __row / __list, .ggis-company__duo, .ggis-cta__grid, .ggis-solutions__row)
   via the .ggis-grid mechanism near the top of this file. ggis.css stays the
   single source of truth for templates + chrome. Only what ggis.css can't
   express for the Divi DOM lives below:
   (a) flex-direction column on every flex section,
   (b) the full-bleed hero figure that rides on a Row background,
   (c) the Journey timeline (exact .ggis-process markup in a Code module) whose
       wrapper section must go transparent + full-bleed for the GSAP pin,
   (d) Solutions cell alignment + restored index-row padding,
   (e) the Contact fact list, rebuilt from <dl> into an editable div/<p> block.
   ========================================================================== */

/* Hero — full-bleed figure. The photo is the figure Row's background image;
   break the row out of the 1800px frame + side gutters and give it the
   design's aspect-ratio (4/3 -> 16/9) with a cover fit. The lone column just
   holds the height. The hero's own bottom padding stays zero — the next
   section brings its top padding. */
.ggis-abouthero.et_pb_section { padding-bottom: 0 !important; }
.ggis-abouthero__figure.et_pb_row {
  width: 100% !important;
  max-width: none !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  margin-top: 3rem;
  aspect-ratio: 4 / 3;
  background-size: cover !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
}
@media (min-width: 48rem) {
  .ggis-abouthero__figure.et_pb_row { aspect-ratio: 16 / 9; }
}
.ggis-abouthero__figure.et_pb_row > .et_pb_column { display: none; }

/* Every GGIS section imports with a native Flex layout style; force column
   direction so their rows keep stacking (Divi's flex default is row). !important
   beats any per-section flex-direction Divi may emit. */
.et_pb_section[class*="ggis-"] { flex-direction: column !important; }

/* --- Mobile: collapse the 2-column layout grids -----------------------------
   Divi stamps a 3-column grid template on these ggis-grid rows, and ggis.css
   only sets the real template at its desktop breakpoint — so on mobile the rows
   inherit Divi's grid and crush the content into slivers. Reset each to one
   column below its breakpoint; the cells then stack. NOT applied to
   .ggis-solutions__row, which keeps its own mobile index template. */
@media (max-width: 63.99rem) {
  .ggis-abouthero__headrow.et_pb_row,
  .ggis-values__grid.et_pb_row,
  .ggis-cta__grid.et_pb_row,
  .ggis-duo__grid.et_pb_row,
  .ggis-module.et_pb_row,
  .ggis-steps-layout.et_pb_row,
  .ggis-feature-highlights.et_pb_row { grid-template-columns: 1fr !important; }
}
@media (max-width: 47.99rem) {
  .ggis-company__duo.et_pb_row,
  .ggis-assure__grid.et_pb_row,
  .ggis-problem__grid.et_pb_row,
  .ggis-cards--two.et_pb_row,
  .ggis-cards--three.et_pb_row { grid-template-columns: 1fr !important; }
}

/* Our Journey — pinned horizontal timeline with EDITABLE card columns. The Divi
   section IS .ggis-process (ggis.css pins + centres it and paints the tint band);
   the head is a small Code module, and the track is a Divi Row whose card columns
   the pin JS (ggis-motion.js, scrubs .ggis-process-track by x) moves sideways.
   The card body Text module holds the milestone title + copy as editable text. */
.ggis-process.et_pb_section { background: var(--ggis-canvas-tint); }
.ggis-process .et_pb_module { margin-bottom: 0 !important; }

/* Desktop + motion: turn the track Row into the wide horizontal flex the JS
   scrubs — cards fixed at 30rem, no wrap, so track.scrollWidth exceeds the
   viewport (that's the condition the pin JS checks). Below 64rem the columns
   stack into the mockup's calm vertical fallback. */
@media (min-width: 64rem) {
  .ggis-process-track.et_pb_row {
    display: flex !important;
    flex-direction: row !important;
    flex-wrap: nowrap !important;
    width: max-content !important;
    max-width: none !important;
    gap: 2rem;
    /* Divi's flex section centres the track, which puts its left edge OFF the
       left of the viewport — the pin JS then computes distance() <= 0 and never
       fires. Left-align it and offset to the centred-1800 gutter so it starts
       where the heading does and scrollWidth genuinely exceeds the viewport. */
    align-self: flex-start !important;
    margin-left: max(0px, calc((100% - var(--ggis-site)) / 2)) !important;
    margin-right: 0 !important;
    padding-right: 0 !important;
  }
  .ggis-process-track.et_pb_row > .et_pb_column {
    width: 30rem !important;
    flex: 0 0 30rem !important;
    margin: 0 !important;
    float: none !important;
  }
}

/* Values note (image + lede): the mockup pushes it to the column foot with
   margin-top:auto, but that can't act inside a Divi Text module (block flow),
   so give it a fixed top gap at desktop instead. */
@media (min-width: 64rem) {
  .ggis-values__note { margin-top: 3rem !important; }
}

/* Our Solutions — native nested list: Row(flex) > Column(.ggis-solutions__list)
   > a Row per item. ggis.css .ggis-solutions__row supplies the grid, hairline,
   hover shift and (via .ggis-reveal) the fade-up. Here we: free each item row's
   cell columns as grid items, right-align the meta + arrow cells (the grid item
   is the column, not the inner span), and restore the 1.75rem index padding the
   global row-padding reset removes. The nested rows also get the side gutter
   zeroed (the list column already sits inside the section gutter). */
.ggis-solutions__row.et_pb_row {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  width: 100% !important;
  max-width: none !important;
}
@media (max-width: 47.99rem) {
  .ggis-solutions__row.et_pb_row { grid-template-columns: auto 1fr auto; }
}
/* Item-row padding must out-specify the general row gutter/zero rules (which
   still match nested rows on an un-rebuilt theme): no side gutter, 1.75rem top
   + bottom for breathing room. Target the nested-row class for a robust win. */
.et_pb_section.ggis-solutions .et_pb_row.et_pb_row_nested.ggis-solutions__row {
  padding: 1.75rem 0 !important;
}
.ggis-solutions__cell-meta { justify-self: end; text-align: right; }
.ggis-solutions__cell-arrow { justify-self: end; }
@media (max-width: 47.99rem) {
  .ggis-solutions__cell-meta { grid-column: 2; justify-self: start; text-align: left; }
}
/* Divi tags the card text modules et_pb_bg_layout_light (dark text); the index
   title sits on the dark band, so force it to the canvas colour. */
.ggis-solutions .ggis-solutions__row-title { color: var(--ggis-canvas) !important; }

/* Contact fact list — rebuilt from <dl>/<dt>/<dd> into an editable div/<p>
   block; mirror the mockup's dt/dd type. */
.ggis-cta__facts { display: grid; gap: 1.5rem; }
.ggis-cta__fact-dt {
  font-family: var(--ggis-font-sans);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(250, 247, 240, 0.6);
}
.ggis-cta__fact-dd {
  margin-top: 0.5rem;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: rgba(250, 247, 240, 0.85);
}
.ggis-cta__fact-dd a:hover { color: var(--ggis-gold-soft); }

/* ==========================================================================
   Service sub-pages (Integrated FM, Command Centre, AI Attendance) — 2026-08.
   Native builds reusing the About patterns; ggis.css supplies the section
   layouts + templates. These rules add what the Divi DOM needs on top; the
   mobile-collapse block above already resets their 2-col grids to one column.
   ========================================================================== */

/* Assurance stat boxes — the value → note gap (0.6rem in ggis.css) reads too
   tight beneath the big italic display value, so give it more room. */
.ggis-assure__note { margin-top: 1.25rem !important; }

/* Framed screenshots (.ggis-screen Image modules) — the 16:9 frame from ggis.css
   with the image CONTAINED (never cropped). Like .ggis-figure but contain. */
.ggis-screen.et_pb_image { width: 100%; margin: 0; }
.ggis-screen .et_pb_image_wrap { position: absolute; inset: 0; display: block; }
.ggis-screen .et_pb_image_wrap img,
.ggis-screen img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* Steps timeline (Command Centre #implementation, AI Attendance #how) is now a
   fully native section — .ggis-steps-layout is a 2-col ggis-grid row (reset to
   1 col by the mobile-collapse block; ggis.css sets the desktop 0.72fr/1fr), the
   image an Image module, each step its own Text module. Only fix needed: the
   step number was promoted <span>→<p> for TinyMCE safety, so clear its default
   paragraph margin or it skews the num|body grid cell. */
.ggis-step__num { margin: 0 !important; }

/* Command Centre "two modules" — each module is a nested Row (Row>Column>Row)
   inside the .ggis-modules column; free them like the Solutions nested rows so
   they fill the column at the ggis.css template width. */
.ggis-modules-section .et_pb_row.et_pb_row_nested.ggis-module {
  width: 100% !important;
  max-width: none !important;
  padding: 0 !important;
}

/* Landscape Selected Work — editorial vertical stagger on the project columns. */
@media (min-width: 64rem) {
  .ggis-projects-section .ggis-project--p2.et_pb_column { margin-top: 7rem; }
  .ggis-projects-section .ggis-project--p3.et_pb_column { margin-top: 2rem; }
  .ggis-projects-section .ggis-project--p4.et_pb_column { margin-top: 7rem; }
  .ggis-projects-section .ggis-project--p5.et_pb_column { margin-top: 3rem; }
}

/* Global header logo swap. The ggis-navbar Code module is one shared Theme
   Builder header, so the light/ink lockup can't be hardcoded per page. Base
   state = transparent bar + LIGHT lockup (correct over the home page's dark
   hero). Every inner/light-hero page — anything that isn't the home/front page
   — gets the solid ivory chrome + INK lockup from load, mirroring .is-scrolled.
   (is-scrolled still takes over past 120px everywhere.) If the home page id is
   not 34, update :not(.page-id-34) to match. */
body:not(.home):not(.page-id-34) .ggis-navbar {
  background: rgba(250, 247, 240, 0.95);
  border-bottom-color: var(--ggis-line);
  color: var(--ggis-ink);
  backdrop-filter: blur(6px);
}
body:not(.home):not(.page-id-34) .ggis-brand__logo--light { display: none; }
body:not(.home):not(.page-id-34) .ggis-brand__logo--ink { display: block; }
body:not(.home):not(.page-id-34) .ggis-navbar__cta {
  background: var(--ggis-green-800);
  color: var(--ggis-canvas);
  box-shadow: none;
}

/* ==========================================================================
   Global Footer — native rebuild (2026-08-03). The single Code module is now
   native modules: logo = Image, each block = its own Text module inside 4 real
   columns, bar + ghost = their own rows. ggis.css carries all .ggis-footer*
   chrome (green-950 band, grid template, hairline, ghost); these rules only
   reconcile Divi's column / margin / padding defaults to match the static build.
   ========================================================================== */
/* Divi's section wrapper adds default padding; the grid + bar rows own the
   vertical rhythm (as the static <footer> did), so zero the section's own. */
.et_pb_section.ggis-footer {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  /* et_flex_section adds row-gap:var(--vertical-gap) (60px) between the grid, bar
     and ghost rows. The static footer has no gap - each row's own padding carries
     the rhythm - so the gap stacked 120px of dead space into the band. */
  row-gap: 0 !important;
}
/* Kill Divi module bottom-margins in the footer — spacing comes from ggis.css
   element margins (.ggis-footer__tagline / __address / col ul / backtotop). */
.ggis-footer .et_pb_module { margin-bottom: 0 !important; }

/* 4-col brand/office/nav grid: the general ggis-grid rule frees the columns;
   force grid + restore the 5rem vertical padding the zero-row rule strips (the
   template, 3rem gap and 1→2→4 col responsive all come from ggis.css). */
.ggis-footer .et_pb_row.ggis-grid { display: grid !important; }
.et_pb_section.ggis-footer .ggis-footer__grid.et_pb_row {
  padding-top: 5rem !important;
  padding-bottom: 5rem !important;
}
/* Mobile (<48rem): the footer's Divi grid row keeps a multi-col template below its
   own breakpoint (rendered 3 cols at 375px) — force one column so the four columns
   stack cleanly. */
@media (max-width: 47.99rem) {
  .et_pb_section.ggis-footer .ggis-footer__grid.et_pb_row { grid-template-columns: 1fr !important; }
}

/* Bottom bar: restore the 2rem padding; the two legal lines live in one Text
   module, so flex its inner wrapper to sit them left/right (the row's own flex
   children are Divi columns, not the <p>s). Hairline top comes from ggis.css. */
.et_pb_section.ggis-footer .ggis-footer__bar.et_pb_row {
  padding-top: 2rem !important;
  padding-bottom: 2rem !important;
}
.ggis-footer .ggis-footer__bar .et_pb_text_inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

/* Ghost wordmark row: full-bleed + no padding so the 15vw wordmark centres across
   the footer and the section's overflow:hidden clips it, as in the static build. */
.et_pb_section.ggis-footer .et_pb_row.ggis-footer__ghostrow:not(.et_pb_row_nested) {
  max-width: none !important;
  padding: 0 !important;
}
.et_pb_section.ggis-footer .ggis-footer__ghostrow .et_pb_column { padding: 0 !important; }

/* Header stacking. Divi wraps the Theme Builder header in .et-l--header (static,
   z:auto), while the page's content columns carry z-index:2 and come later in the
   DOM — so wherever a column sits in the navbar band, content paints OVER the fixed
   .ggis-navbar (its z:50 is trapped inside the header column's own z:2 stacking
   context, not competing at the page level). Lift the whole header layer above the
   body; the navbar's internal order (bar 50, flyout 60) is untouched. Below the WP
   admin bar (99999), which is admin-only. */
.et-l--header { position: relative; z-index: 9999; }

/* Header height collapse. The navbar is position:fixed (out of flow), but the
   Divi wrappers AROUND it are not: .et-l--header > inner content > section
   .ggis-shell (an et_flex_section with padding: var(--section-padding) = 56px
   top+bottom) > row > column > Code module. That chain renders as an empty
   in-flow ivory band (~150px) above the hero, pushing every page down. In the
   static build the navbar hangs off <body> with no wrapper, so there was no
   band. Collapse the whole chain to zero height and strip Divi's section
   padding/row-gaps; the fixed navbar is unaffected (it ignores wrapper
   geometry) and the Theme Builder keeps its slot in the DOM for WP.

   v4.20.1: the first attempt set font-size:0 on .et_pb_code_inner, which
   INHERITS into the fixed navbar and squished its labels/CTA, and the blanket
   padding:0 !important on .et_pb_module also flattened the dropdown panels'
   spacing (both live under .et_pb_code_inner). The band's only in-flow
   content is whitespace text between tags, so the line-box neutralisation is
   scoped to a direct-text-only trick that cannot reach inside .ggis-navbar:
   display:contents on the wrappers (they carry no styles the navbar needs)
   removes the wrappers from layout entirely, and the code module itself
   becomes 0-height via max-height + overflow:visible. */
.et-l--header .et_pb_section.ggis-shell {
  padding: 0 !important;
  min-height: 0;
}
.et-l--header .et_pb_section.ggis-shell .et_pb_row {
  margin: 0 !important;
  padding: 0 !important;
  min-height: 0;
  display: block;
}
.et-l--header .et_pb_section.ggis-shell .et_pb_column,
.et-l--header .et_pb_section.ggis-shell .et_pb_module {
  margin: 0 !important;
  padding: 0 !important;
  min-height: 0;
}
.et-l--header .et_pb_section.ggis-shell .et_pb_code_inner {
  display: contents;
}

/* --- TranslatePress language switcher ---------------------------------------
   Restyle TP's floating dropdown into a GGIS micro-caps pill: [flag] EN / [flag]
   BM shown inline (both languages at once — no click-to-open for two langs),
   current in ink, other muted, gold on hover, with a hairline divider. Flags
   kept, sized down with a hairline ring. Short codes are injected via ::after
   keyed on each item's stable `title`, so they stay correct after switching.

   Right edge: ggis-motion.js pins it to the 1800px content frame (footer/nav/
   hero). The responsive `right` below is the no-JS / reduced-motion fallback and
   matches the section gutter (24 / 40 / 64 / 96px). On scroll-down the pill
   slides past the bottom edge via .ggis-trp-tucked (also ggis-motion.js). */
.trp-language-switcher.trp-floating-switcher {
  bottom: 1.5rem !important;
  right: 1.5rem !important;
  top: auto !important;
  left: auto !important;
  flex-direction: row !important;
  align-items: center !important;
  width: auto !important;
  height: auto !important;
  max-height: none !important;
  padding: 0 !important;
  overflow: visible !important;
  background: rgba(253, 251, 247, 0.95) !important; /* canvas-bright @ 95% */
  border: 1px solid var(--ggis-line) !important;
  border-radius: 999px !important;
  box-shadow: 0 10px 28px rgba(23, 27, 22, 0.1) !important;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.45s ease !important;
  will-change: transform;
}
@media (min-width: 48rem) { .trp-language-switcher.trp-floating-switcher { right: 2.5rem !important; } }
@media (min-width: 80rem) { .trp-language-switcher.trp-floating-switcher { right: 4rem !important; } }
@media (min-width: 96rem) { .trp-language-switcher.trp-floating-switcher { right: 6rem !important; } }

.trp-language-switcher.trp-floating-switcher.ggis-trp-tucked {
  transform: translateY(calc(100% + 2.5rem)) !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

.trp-language-switcher.trp-floating-switcher .trp-language-switcher-inner {
  flex-direction: row !important;
  align-items: center !important;
  height: auto !important;
  width: auto !important;
}

/* Reveal the second language inline (TP hides it via max-height:0). */
.trp-language-switcher.trp-floating-switcher .trp-switcher-dropdown-list {
  max-height: none !important;
  height: auto !important;
  overflow: visible !important;
  flex-direction: row !important;
  position: static !important;
  width: auto !important;
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  margin: 0 !important;
  opacity: 1 !important;
  visibility: visible !important;
  transform: none !important;
}

.trp-language-switcher.trp-floating-switcher .trp-ls-shortcode-arrow,
.trp-language-switcher.trp-floating-switcher svg { display: none !important; }

.trp-language-switcher.trp-floating-switcher .trp-language-item {
  display: flex !important;
  align-items: center !important;
  gap: 0.5rem !important;
  padding: 0.72rem 0.95rem !important;
  margin: 0 !important;
  background: transparent !important;
  height: auto !important;
  border: 0 !important;
}

.trp-language-switcher.trp-floating-switcher .trp-flag-image {
  display: inline-block !important;
  width: 17px !important;
  height: 13px !important;
  border-radius: 2px !important;
  object-fit: cover !important;
  margin: 0 !important;
  box-shadow: 0 0 0 1px rgba(23, 27, 22, 0.06);
  flex: 0 0 auto;
}

/* Hide TP's full language name; show a GGIS micro-caps short code instead. */
.trp-language-switcher.trp-floating-switcher .trp-language-item-name {
  font-size: 0 !important;
  line-height: 1 !important;
  display: inline-block !important;
}
.trp-language-switcher.trp-floating-switcher .trp-language-item-name::after {
  font-family: var(--ggis-font-sans);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1;
  color: var(--ggis-ink-faint);
  transition: color 0.2s ease;
}
.trp-language-switcher.trp-floating-switcher .trp-language-item[title="English"] .trp-language-item-name::after { content: "EN"; }
.trp-language-switcher.trp-floating-switcher .trp-language-item[title="Bahasa Melayu"] .trp-language-item-name::after { content: "BM"; }
.trp-language-switcher.trp-floating-switcher .trp-language-item__current .trp-language-item-name::after { color: var(--ggis-ink); }
.trp-language-switcher.trp-floating-switcher .trp-language-item:hover .trp-language-item-name::after { color: var(--ggis-gold-deep); }

/* Hairline divider between the two languages. */
.trp-language-switcher.trp-floating-switcher .trp-switcher-dropdown-list .trp-language-item { position: relative; }
.trp-language-switcher.trp-floating-switcher .trp-switcher-dropdown-list .trp-language-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  height: 1rem;
  width: 1px;
  background: var(--ggis-line);
}

@media (prefers-reduced-motion: reduce) {
  .trp-language-switcher.trp-floating-switcher { transition: none !important; }
  .trp-language-switcher.trp-floating-switcher.ggis-trp-tucked {
    transform: none !important;
    opacity: 1 !important;
    pointer-events: auto !important;
  }
}

/* ============================================================================
   NATIVE DIVI MENU MODULE -> GGIS skin  (TRIAL, 2026-08-06, v4.3.4)
   Dresses a stock Divi 5 Menu module (logo + WP menu + a Button CTA) in the
   GGIS navbar look, so the nav is client-editable via Appearance -> Menus while
   keeping the design. Mirrors the approved .ggis-nav flyout in ggis.css.

   Everything is scoped to the header SECTION's .ggis-menu-header class, so it is
   INERT until that class exists -> the current Code-module header (.ggis-navbar)
   is untouched. Works regardless of the Menu module's own class / a mistyped CTA
   class, because we target Divi's own menu classes under .ggis-menu-header.

   Verified live against the real Divi 5 menu DOM on /sample-page/. The scroll
   state (.is-scrolled) is toggled by ggis-motion.js.
   PROMOTION TODO (when this replaces the live header): add an inner-page solid
   rule like the .ggis-navbar one, and top-padding for non-hero pages.
   ---------------------------------------------------------------------------*/

/* -- Header shell: transparent over the hero, solid ivory once scrolled ------ */
.et_pb_section.ggis-menu-header {
  position: fixed; inset: 0 0 auto 0; z-index: 1000;
  padding-top: 0 !important; padding-bottom: 0 !important;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .4s ease, border-color .4s ease, backdrop-filter .4s ease;
}
.et_pb_section.ggis-menu-header.is-scrolled {
  border-bottom-color: var(--ggis-line);
}
/* Solid ivory on scroll. Divi's Theme Builder injects an inline rule
   .et-l--header ... .et_pb_section_0_tb_header { background-color: rgba(255,255,255,0) !important }
   at (0,4,0) specificity, which beats a plain .is-scrolled rule -- so the ivory
   never painted (only the blur showed). This higher-specificity selector wins;
   opaque + no blur so it reads solid over the hero, not frosted. */
.et-l--header .et_builder_inner_content .et_pb_section.ggis-menu-header.is-scrolled {
  background-color: #faf7f0 !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
/* Logged-in WP admin bar: drop the fixed header below it so it isn't hidden. */
body.admin-bar .et_pb_section.ggis-menu-header { top: 32px; }
@media screen and (max-width: 782px) { body.admin-bar .et_pb_section.ggis-menu-header { top: 46px; } }
/* Match the original navbar height (~96px, --ggis-header-h) so the bar isn't
   cramped and the logo / nav / actions sit with the same breathing room. Without
   this the Menu module collapses to ~60px and looks nothing like .ggis-navbar. */
.ggis-menu-header .et_pb_menu_inner_container { min-height: var(--ggis-header-h, 6rem); align-items: center; }

/* Center the nav between the logo (left) and the phone + CTA (right), desktop. */
@media (min-width: 981px) {
  .ggis-menu-header .et_pb_menu_inner_container { position: relative; }
  .ggis-menu-header .et_pb_menu__wrap { position: absolute; left: 50%; transform: translateX(-50%); }
}
/* header inner row = the 1800 frame + responsive gutter */
.ggis-menu-header .et_pb_row:not(.et_pb_row_nested) {
  width: 100% !important; max-width: var(--ggis-site) !important; margin-inline: auto !important;
  padding-top: 0 !important; padding-bottom: 0 !important;
  padding-left: 1.5rem !important; padding-right: 1.5rem !important;
}
@media (min-width: 48rem) { .ggis-menu-header .et_pb_row:not(.et_pb_row_nested) { padding-left: 2.5rem !important; padding-right: 2.5rem !important; } }
@media (min-width: 80rem) { .ggis-menu-header .et_pb_row:not(.et_pb_row_nested) { padding-left: 4rem !important; padding-right: 4rem !important; } }
@media (min-width: 96rem) { .ggis-menu-header .et_pb_row:not(.et_pb_row_nested) { padding-left: 6rem !important; padding-right: 6rem !important; } }

/* -- Logo: painted from the theme's bundled SVGs (no Media Library / SVG
      upload needed), swapping light -> ink with the scroll state. ------------ */
.ggis-menu-header .et_pb_menu__logo {
  display: block !important;
  width: 9rem; height: 2.75rem;
  background-image: url(../img/ggis-logo-light.svg);
  background-size: contain; background-repeat: no-repeat; background-position: left center;
}
.ggis-menu-header .et_pb_menu__logo img { display: none !important; }
.ggis-menu-header.is-scrolled .et_pb_menu__logo { background-image: url(../img/ggis-logo-ink.svg); }

/* -- Top-level links: GGIS micro-caps, colour follows the header state ------- */
.ggis-menu-header .et_pb_menu__menu > nav > ul.et-menu { display: flex; align-items: center; gap: 2.25rem; }
.ggis-menu-header .et-menu > li { margin: 0; padding: 0; }
.ggis-menu-header .et-menu > li > a {
  font-family: var(--ggis-font-sans);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .9;
  transition: opacity .3s ease, color .3s ease;
}
.ggis-menu-header .et-menu > li > a:hover { opacity: .55; }
.ggis-menu-header:not(.is-scrolled) .et-menu > li > a { color: var(--ggis-canvas); }
.ggis-menu-header.is-scrolled .et-menu > li > a { color: var(--ggis-ink); }
/* Phone: a Divi Link module (et_pb_link) placed immediately BEFORE the Button
   module, holding the number as a tel: link. It's the only Link module in the
   header, so we target it directly -- no CSS class to get right. margin-left:auto
   pins the phone + CTA together at the far right (the navbar's actions cluster)
   while the nav stays left; the number reads plain and follows the scroll colour,
   matching .ggis-navbar__phone (Instrument Sans, fs-meta, opacity .85). */
.ggis-menu-header .et_pb_menu_inner_container .et_pb_link {
  margin: 0 0 0 auto !important; padding: 0 !important; display: flex !important; align-items: center;
}
.ggis-menu-header .et_pb_link { opacity: .85; }
.ggis-menu-header .et_pb_link,
.ggis-menu-header .et_pb_link p,
.ggis-menu-header .et_pb_link a {
  font-family: var(--ggis-font-sans) !important;
  font-size: var(--fs-meta) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  line-height: 1 !important;
  margin: 0 !important;
  white-space: nowrap;
  text-decoration: none !important;
}
.ggis-menu-header:not(.is-scrolled) .et_pb_link,
.ggis-menu-header:not(.is-scrolled) .et_pb_link p { color: var(--ggis-canvas) !important; }
.ggis-menu-header.is-scrolled .et_pb_link,
.ggis-menu-header.is-scrolled .et_pb_link p { color: var(--ggis-ink) !important; }
.ggis-menu-header .et_pb_link + .et_pb_button_module_wrapper { margin-left: 1.1rem !important; }
/* Phone hides below the desktop breakpoint, matching .ggis-navbar__phone (@64rem):
   below 1024px the desktop menu collapses to the hamburger, so the phone goes too. */
@media (max-width: 63.99rem) {
  .ggis-menu-header .et_pb_menu_inner_container .et_pb_link { display: none !important; }
}

/* -- Dropdown (sub-menu) = the GGIS flyout panel ---------------------------- */
.ggis-menu-header .et-menu .sub-menu {
  width: max-content !important;
  min-width: 0 !important;
  padding: .3rem !important;
  background: var(--ggis-canvas-bright) !important;
  border: 1px solid var(--ggis-line) !important;
  border-radius: 1rem !important;
  box-shadow: var(--ggis-shadow-card, 0 22px 48px -26px rgba(18, 33, 20, .45)) !important;
}
.ggis-menu-header .et-menu .sub-menu li { margin: 0; padding: 0; width: 100%; float: none; }
.ggis-menu-header .et-menu .sub-menu li a {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  box-sizing: border-box;
  padding: .75rem 1rem !important;
  line-height: 1.3;
  border-radius: .6rem;
  font-family: var(--ggis-font-sans);
  font-size: var(--fs-meta);
  font-weight: 500;
  letter-spacing: .02em;
  text-transform: none;
  color: var(--ggis-ink) !important;
  white-space: nowrap;
  transition: background-color .2s ease, color .2s ease;
}
.ggis-menu-header .et-menu .sub-menu li a:hover {
  background: var(--ggis-canvas-tint) !important;
  color: var(--ggis-green-800) !important;
}
/* Nested sub-menu (Integrated FM -> Command Centre / AI Attendance) flies left,
   flush against the parent panel. The ::before is an invisible bridge so moving
   the pointer across to it never crosses a dead zone that closes the menu. The
   has-children link gets extra right padding so its chevron never crowds the label. */
.ggis-menu-header .et-menu .sub-menu .menu-item-has-children > a { padding-right: 1rem !important; }
/* Divi's chevron (::after, ETmodules glyph) is position:absolute by default, which
   floats it at the panel edge and lets a long label collide with it. Make it a
   normal flex child so it sits right after the label with a small gap. */
.ggis-menu-header .et-menu .sub-menu .menu-item-has-children > a::after {
  position: static !important; margin: 0 !important; transform: none !important;
  top: auto !important; right: auto !important; left: auto !important;
  font-size: .8rem !important; line-height: 1 !important; opacity: .55; flex: 0 0 auto;
}
.ggis-menu-header .et-menu .sub-menu .menu-item-has-children > .sub-menu {
  top: -.6rem; left: auto; right: 100%; margin-right: 0;
}
.ggis-menu-header .et-menu .sub-menu .menu-item-has-children > .sub-menu::before {
  content: ""; position: absolute; top: 0; bottom: 0; right: -16px; width: 16px;
}

/* -- CTA: GGIS pill button beside the menu ---------------------------------- */
.ggis-menu-header .et_pb_button {
  font-family: var(--ggis-font-sans) !important;
  font-size: var(--fs-meta) !important;
  font-weight: 500 !important;
  letter-spacing: .08em !important;
  text-transform: uppercase !important;
  padding: .8rem 1.4rem !important;
  border-radius: 999px !important;
  border: 1px solid transparent !important;
  background: var(--ggis-green-800) !important;
  color: var(--ggis-canvas) !important;
  transition: background-color .3s ease !important;
}
.ggis-menu-header .et_pb_button:hover { background: var(--ggis-green-900) !important; }
.ggis-menu-header .et_pb_button:after { display: none !important; }

/* -- Mobile: hamburger colour follows state; panel = ivory card (first cut) -- */
.ggis-menu-header:not(.is-scrolled) .et_mobile_nav_menu .mobile_menu_bar:before { color: var(--ggis-canvas); }
.ggis-menu-header.is-scrolled .et_mobile_nav_menu .mobile_menu_bar:before { color: var(--ggis-ink); }
.ggis-menu-header .et_mobile_menu {
  background: var(--ggis-canvas-bright) !important;
  border: 1px solid var(--ggis-line) !important;
}
.ggis-menu-header .et_mobile_menu li a {
  font-family: var(--ggis-font-sans);
  color: var(--ggis-ink) !important;
  text-transform: none;
}
/* ===========================================================================
   LEGACY COMPAT — classes still used by imported Divi layouts that the current
   design system no longer ships. Rules live HERE, never in css/ggis.css, so a
   sync from the static site can never clobber them.

   .ggis-synergy__quote — the Regional Synergy band was rebuilt on the static
   site as .ggis-synergy__statement/__lead/__body, but home.et_builder.json and
   home-full.et_builder.json still carry the old single-quote markup. Keeping
   its original styling so those layouts keep rendering until they are
   re-exported against the new markup.
=========================================================================== */
.ggis-synergy__quote {
  margin-top: 4rem;
  max-width: 60ch;
  font-family: var(--ggis-font-display);
  font-size: var(--fs-title-lg);
  font-style: italic;
  font-weight: 340;
  line-height: 1.5;
  color: rgba(250, 247, 240, 0.85);
}

/* ===========================================================================
   v1.1 RECONCILE - HomePage_Brief 20.8 / ABOUT US 20.8 structures.
   The blocks above were calibrated to the pre-brief designs; these override
   them for the sections regenerated into divi/library/v1.1/.
   =========================================================================== */

/* --- Integrated Services -------------------------------------------------
   Was 3 gapped cards; now FOUR cards in a full-bleed CONNECTED band - the
   images run edge-to-edge and touch (column-gap 0, no side padding on the
   row), with only the captions inset. Head is centred over the band. */
/* In the design this head is a flex column whose CHILDREN are the heading and the
   lead, so each shrinks to fit and centres on its own measure. In Divi the flex
   child is the column, and the modules inside it are full-width blocks - so the
   centred text sat in a 1419px box instead of its natural 975px and wrapped
   differently. Push the flex down one level so the modules are the flex items. */
.ggis-services__head > .et_pb_column {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.ggis-services .et_pb_row.ggis-services__head {
  display: flex !important;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1.5rem;
  max-width: none !important;
  width: 100% !important;
  padding-inline: 2em !important;
}
.et_pb_section.ggis-services .et_pb_row.ggis-grid:not(.et_pb_row_nested) {
  grid-template-columns: 1fr;
  gap: 3rem 0 !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  max-width: none !important;
  width: 100% !important;
}
@media (min-width: 768px) {
  .et_pb_section.ggis-services .et_pb_row.ggis-grid:not(.et_pb_row_nested) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1280px) {
  .et_pb_section.ggis-services .et_pb_row.ggis-grid:not(.et_pb_row_nested) {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 3.5rem 0 !important;
  }
}
/* captions carry their own em inset; the figures stay flush */
.ggis-services .et_pb_row.ggis-grid .ggis-card__body {
  padding-inline: 2em;
}

/* --- Cross-border synergy -------------------------------------------------
   The middle column must fit the leaf node (9.5rem) plus a wire either side.
   The old `auto` middle let the side columns take their full 26rem and
   squeezed the node until it overlapped the rings at 1024. */
.ggis-synergy .et_pb_row.ggis-synergy__head {
  text-align: center;
  max-width: none !important;
}
/* The design caps this map at 82rem inside .ggis-container, i.e.
   width = min(82rem, container content). Divi's row IS the container here - it
   carries the responsive gutter as PADDING and Divi stamps width:100%!important on
   it (load-bearing: the row is a flex item of an et_flex_section with
   align-items:center, so width:auto would shrink it to fit-content). With
   border-box that makes content = min(rowWidth, max-width) - 2*gutter, so the cap
   has to be 82rem PLUS the gutter of the moment. Two earlier attempts were wrong:
   box-sizing:content-box made 82rem the content width and the gutter piled on top
   (row measured 1440px at a 1366px viewport and pushed the right orb off-screen),
   and capping the tracks instead let the middle take its max while the sides
   shrank (371|480|371 rather than the design's 416|406|416). Gutter tiers are
   2.5 / 4 / 6rem, so the cap is 87 / 90 / 94rem. Verified against the static build
   at 1366 and 1626: connector and wires match to the pixel, no overflow. */
@media (min-width: 64rem) {
  .ggis-synergy .et_pb_row.ggis-grid {
    grid-template-columns: minmax(0, 26rem) minmax(15rem, 1fr) minmax(0, 26rem);
    gap: 0 !important;
    box-sizing: border-box;
    max-width: 87rem !important;
    margin-inline: auto;
  }
}
@media (min-width: 80rem) {
  .ggis-synergy .et_pb_row.ggis-grid { max-width: 90rem !important; }
}
@media (min-width: 96rem) {
  .ggis-synergy .et_pb_row.ggis-grid { max-width: 94rem !important; }
}
/* the orb column holds the ring wrapper; Divi's text wrapper must not clip it */
.ggis-synergy .ggis-synergy__orb .et_pb_text_inner,
.ggis-synergy .ggis-synergy__orb .et_pb_module {
  overflow: visible !important;
}
.ggis-synergy .et_pb_row.ggis-synergy__statement {
  text-align: center;
  max-width: 68ch !important;
  box-sizing: content-box;
  margin-inline: auto;
}

/* --- Trust strip ----------------------------------------------------------
   Cards are now .ggis-statcard (icon + label replacing the old top rule). The
   4-col grid above still applies; just stop Divi's module margin stacking. */
.ggis-trust .et_pb_module {
  margin-bottom: 0 !important;
}

/* --- Solutions index --------------------------------------------------------
   Each row is its own nested Divi Row + Text module, so every <a> is an only
   child and ggis.css's .ggis-solutions__row:last-child rule (the closing
   hairline) matched ALL of them, doubling the rule between rows. Keep it on the
   final row only, as in the static build where the four links are siblings. */
.ggis-solutions__list > .et_pb_row:not(:last-child) .ggis-solutions__row {
  border-bottom: 0;
}

/* Nested rows keep Divi's own vertical padding (the general rule that zeroes it
   excludes .et_pb_row_nested on purpose). Here each nested row is just a carrier
   for one <a> that already owns its padding-block, so Divi's 29.6px top and
   bottom added ~59px per row and pushed the band 337px past the design. */
.ggis-solutions__list > .et_pb_row_nested {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* --- About hero image ---------------------------------------------------------
   The design marks this figure "full-bleed": it sits OUTSIDE .ggis-container and
   runs edge to edge. The generic gutter rule (0,4,0 + !important) was insetting it
   by 96px, so this needs to outrank it - hence the extra .et_pb_section qualifier
   and :not(.et_pb_row_nested), same shape as the Services band fix. */
.et_pb_section.ggis-abouthero .et_pb_row.ggis-abouthero__figurerow:not(.et_pb_row_nested) {
  padding-left: 0 !important;
  padding-right: 0 !important;
  width: 100% !important;
  max-width: none !important;
}

/* --- Text-module alignment ----------------------------------------------------
   Divi bakes `text-align: start` into EVERY Text module's generated CSS
   (.et_pb_text_31,.et_pb_text_32,… in the et-cache files), which load last and
   sit at (0,1,0) - so a centred row could not centre its own modules and the
   Services and Synergy heads stayed left-aligned inside a centred container.
   The design never sets alignment per module, so hand it back to the container. */
.et_pb_section[class*="ggis-"] .et_pb_text {
  text-align: inherit;
}

/* The map centres its grid items (`justify-items: center` in ggis.css) and the
   design's connector re-stretches itself with `width: 100%`. That works in the
   static DOM because the connector IS the grid item. In Divi the grid item is the
   COLUMN and the connector sits three levels below it, so `width: 100%` resolved
   against a column that had already shrunk to fit-content: 192px instead of the
   480px track. The wires are `flex: 1` inside a connector whose gap (2 x 1.25rem)
   then consumed every remaining pixel, so both computed to 0 and the dashed lines
   either side of the leaf node simply vanished. Stretching the columns into their
   tracks restores connector 480 / wires 144 each, matching the static build. */
.ggis-synergy .et_pb_row.ggis-synergy__map > .et_pb_column {
  justify-self: stretch;
}

/* --- Hero headline descender ---------------------------------------------------
   .line-mask carries padding-bottom:0.25em (ggis.css) to stop GSAP's overflow:clip
   shaving descenders. `em` resolves against the MASK's own font-size, and while the
   hero class sits on the Divi module the mask is created outside the <h1> - so 0.25em
   was 0.25 x 17px, not 0.25 x 92px, and the g in "Management" got cut. Give the mask
   the headline's own size so em resolves correctly. The mask holds no text of its own
   (the <h1> inside sets its own size), so this changes nothing visually, and it stays
   a harmless no-op once the class moves onto the <h1>. */
.ggis-hero-headline > .line-mask,
.ggis-hero-headline .line-mask {
  font-size: clamp(2.15rem, 1.1rem + 4.6vw, 5.75rem);
}

/* ...and Divi ships `.et_pb_text > :last-child { padding-bottom: 0 }` at (0,2,0),
   which outranks .line-mask (0,1,0) and stripped the descender padding outright -
   the negative margin survived, the padding did not. That rule only reaches the mask
   because in Divi it is a direct child of the Text module; in the static build the
   mask sits inside the <h1>, where neither rule can touch it. Once the class moves
   onto the <h1> (regenerated layout) this is a no-op, but it keeps any masked
   heading safe if one ever ends up at module level again. */
.et_pb_section[class*="ggis-"] .et_pb_text > .line-mask,
.et_pb_section[class*="ggis-"] .et_pb_text .line-mask {
  padding-bottom: 0.25em;
}

/* --- Divi ultra-wide breakpoint ------------------------------------------------
   Divi ships `@media only screen and (min-width:2250px){.et_pb_section{padding:90px 0}}`.
   That sits at (0,1,0) - the same specificity as .ggis-section - but later in the
   cascade, so on screens 2250px and wider EVERY band lost its 11rem rhythm and
   collapsed to 90px. It never showed up in testing because it only fires above
   2250px. Re-assert the design values one specificity step higher. Sections that
   already have a (0,2,0) !important rule elsewhere (hero, footer) are unaffected. */
@media (min-width: 2250px) {
  .et_pb_section.ggis-section {
    padding-block: 11rem;
  }
  .et_pb_section.ggis-values {
    padding-bottom: 10rem;
  }
  .et_pb_section.ggis-abouthero {
    padding-top: 9.5rem;
  }
  .et_pb_section.ggis-trust {
    padding-block: 3.5rem;
  }
  .et_pb_section.ggis-process {
    padding-block: 0;
  }
}

/* --- CTA backdrop blur ---------------------------------------------------------
   .ggis-cta__grid::before is the blurred panel that lifts the form off the leaf
   artwork (blur 22px + a green tint, masked to an ellipse). It sits at z-index:-1,
   which only works if its parent forms a STACKING CONTEXT - in the static build
   that job is done by `.ggis-cta > .ggis-container { position:relative; z-index:1 }`.
   Divi has no .ggis-container wrapper: the row IS the container, and Divi leaves it
   at z-index:auto. With no context the -1 pseudo escaped upward and painted BENEATH
   the section's leaf ::before/::after, so the blur was invisible. Giving the row an
   explicit z-index rebuilds the context and the panel lands above the leaves, which
   is exactly what backdrop-filter needs to have something to blur. */
.ggis-cta .et_pb_row.ggis-cta__grid {
  position: relative;
  z-index: 1;
}

/* --- Hero content row padding --------------------------------------------------
   Divi ships `.et_block_row { padding: 2% 0 }` at >=981px and `{ padding: 45px 0 }`
   at >=2250px. Both are (0,1,0) - the same weight as .ggis-container and
   .ggis-hero__content - and the ultra-wide one lands later in the cascade, so it won.
   Because it is a `padding` SHORTHAND it also zeroed the horizontal gutter, so the
   hero copy lost both its 9rem/3rem block padding and its side inset (measured
   45px 0 at 2470px). Every other row is already covered - the reset zeroes their
   vertical padding and the gutter rule sets their inset, both with !important - but
   this row is deliberately excluded from that reset, so it needs its own assertion.
   Gutter tiers mirror .ggis-container exactly: 1.5 / 2.5 / 4 / 6rem. */
.et_pb_section.ggis-hero .et_pb_row.ggis-hero__content {
  padding-top: 9rem !important;
  padding-bottom: 3rem !important;
  padding-left: 1.5rem !important;
  padding-right: 1.5rem !important;
}
@media (min-width: 48rem) {
  .et_pb_section.ggis-hero .et_pb_row.ggis-hero__content {
    padding-left: 2.5rem !important;
    padding-right: 2.5rem !important;
  }
}
@media (min-width: 80rem) {
  .et_pb_section.ggis-hero .et_pb_row.ggis-hero__content {
    padding-left: 4rem !important;
    padding-right: 4rem !important;
  }
}
@media (min-width: 96rem) {
  .et_pb_section.ggis-hero .et_pb_row.ggis-hero__content {
    padding-left: 6rem !important;
    padding-right: 6rem !important;
  }
}

/* ===========================================================================
   LANDSCAPE CONSULTANCY page (v1.1)
   Six grid rows plus the Divi-Image-as-figure mapping. Every grid row is marked
   "ggis-grid" in the layout JSON, so the general column-freeing rule near the
   top of this file already applies; these blocks only supply the template, gap
   and breakpoints, copied from the matching rules in ggis.css.
   =========================================================================== */

/* 01 Industry challenge - three risk pillars: 1 / 2 / 3 columns. */
.ggis-risk .et_pb_row.ggis-risk__grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 3rem;
  margin: 4.5rem 0 0;
}
@media (min-width: 48rem) {
  .ggis-risk .et_pb_row.ggis-risk__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 64rem) {
  .ggis-risk .et_pb_row.ggis-risk__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* 02 The Practice - copy | figure. The figure classes sit on the COLUMN here,
   because the column is the grid child the static build styles. */
.ggis-service-intro .et_pb_row.ggis-service-intro__grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 3rem;
  align-items: center;
}
@media (min-width: 64rem) {
  .ggis-service-intro .et_pb_row.ggis-service-intro__grid {
    grid-template-columns: 1.05fr 0.95fr;
    gap: 5rem;
  }
}

/* 03 Capabilities - 1 / 3 image cards. align-items:start so short cards keep
   their 3:2 figures instead of stretching to the tallest. */
.ggis-capabilities .et_pb_row.ggis-capabilities__grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  margin-top: 4.5rem;
  align-items: start;
}
@media (min-width: 48rem) {
  .ggis-capabilities .et_pb_row.ggis-capabilities__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.75rem;
  }
}

/* 04 Project workflow - figure | five-step list. align-items:stretch plus the
   figure release below is what makes the photo track the list's height. */
.ggis-steps-section .et_pb_row.ggis-steps-layout {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  margin-top: 3.5rem;
}
@media (min-width: 64rem) {
  .ggis-steps-section .et_pb_row.ggis-steps-layout {
    grid-template-columns: 0.55fr 1fr;
    gap: 3.5rem;
    align-items: stretch;
  }
  .ggis-steps-section .et_pb_row.ggis-steps-layout > .et_pb_column.ggis-figure {
    aspect-ratio: auto;
    max-height: none;
    min-height: 0;
  }
}

/* 05 Portfolio - 12-column editorial grid. The per-project placements
   (.ggis-project--p1..p4) come from ggis.css and land on the columns. */
.ggis-projects-section .et_pb_row.ggis-projects {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 5rem 0;
  margin-top: 5rem;
}
@media (min-width: 48rem) {
  .ggis-projects-section .et_pb_row.ggis-projects {
    grid-template-columns: repeat(12, 1fr);
    column-gap: 1.5rem;
    row-gap: 7rem;
    margin-top: 7rem;
  }
}

/* 06 What we offer - copy + brochure | eight-item list. */
.ggis-offer .et_pb_row.ggis-offer__grid {
  display: grid !important;
  grid-template-columns: 1fr;
  gap: 3.5rem;
  align-items: start;
}
@media (min-width: 64rem) {
  .ggis-offer .et_pb_row.ggis-offer__grid { grid-template-columns: 1fr 1fr; gap: 6rem; }
}

/* --- Divi Image module used as a ggis figure --------------------------------
   The static markup is <div class="ggis-figure"><img></div>. A Divi Image
   module renders .et_pb_image > .et_pb_image_wrap > img, and the wrap is
   inline-block, so height:100% on the img collapses. Force the wrap to fill its
   module and the img to cover it. Covers both cases: figure classes on the
   Image module (capabilities, portfolio) and on the column (practice,
   workflow), where the module itself must also fill the column. */
.et_pb_section[class*="ggis-"] .ggis-figure .et_pb_image_wrap {
  display: block;
  width: 100%;
  height: 100%;
}
.et_pb_section[class*="ggis-"] .ggis-figure .et_pb_image_wrap > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-figure > .et_pb_image {
  height: 100%;
  margin: 0 !important;
}

/* --- Lists inside Divi modules ---------------------------------------------
   Divi styles lists at .et_pb_module ul / li (0,1,1), which outranks a plain
   .ggis-* class selector (0,1,0) - so the offer list and the step list lose
   their reset and fall back to disc bullets with the flex row collapsed. Both
   live in Code modules, so restate the reset at module scope. Values copied
   from .ggis-offer__list / .ggis-offer__item / .ggis-steps in ggis.css. */
.et_pb_section[class*="ggis-"] .et_pb_module ul.ggis-offer__list,
.et_pb_section[class*="ggis-"] .et_pb_module ol.ggis-steps {
  list-style: none !important;
  padding: 0 !important;
}
.et_pb_section[class*="ggis-"] .et_pb_module ul.ggis-offer__list > li,
.et_pb_section[class*="ggis-"] .et_pb_module ol.ggis-steps > li {
  list-style: none !important;
  list-style-type: none !important;
}
.et_pb_section[class*="ggis-"] .et_pb_module li.ggis-offer__item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding-block: 1.15rem;
}
.et_pb_section[class*="ggis-"] .et_pb_module li.ggis-offer__item > .ggis-offer__mark {
  flex-shrink: 0;
}

/* --- Landscape grids: hard override -----------------------------------------
   Divi 5 lays rows out with `grid-template-columns: repeat(var(--column-count),
   1fr)` on .et_grid_row, so the track count is driven by a custom property, not
   a literal. Setting the property as well as the declaration means the row ends
   up with the right count whichever declaration wins the cascade - and the
   !important closes off Divi's higher-specificity per-row selectors, which are
   built with #main-content and outrank a plain class chain. */
.ggis-risk .et_pb_row.ggis-risk__grid,
.ggis-capabilities .et_pb_row.ggis-capabilities__grid,
.ggis-service-intro .et_pb_row.ggis-service-intro__grid,
.ggis-steps-section .et_pb_row.ggis-steps-layout,
.ggis-offer .et_pb_row.ggis-offer__grid,
.ggis-projects-section .et_pb_row.ggis-projects {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 48rem) {
  .ggis-risk .et_pb_row.ggis-risk__grid {
    --column-count: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  .ggis-capabilities .et_pb_row.ggis-capabilities__grid {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
  .ggis-projects-section .et_pb_row.ggis-projects {
    --column-count: 12;
    grid-template-columns: repeat(12, 1fr) !important;
  }
}
@media (min-width: 64rem) {
  .ggis-risk .et_pb_row.ggis-risk__grid {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
  .ggis-service-intro .et_pb_row.ggis-service-intro__grid {
    --column-count: 2;
    grid-template-columns: 1.05fr 0.95fr !important;
  }
  .ggis-steps-section .et_pb_row.ggis-steps-layout {
    --column-count: 2;
    grid-template-columns: 0.55fr 1fr !important;
  }
  .ggis-offer .et_pb_row.ggis-offer__grid {
    --column-count: 2;
    grid-template-columns: 1fr 1fr !important;
  }
}

/* --- IFM grids: hard override -------------------------------------------------
   Same mechanism as the Landscape block above: Divi 5 drives .et_grid_row with
   `repeat(var(--column-count), 1fr)`, so the custom property is set alongside the
   declaration and !important closes off Divi's #main-content-scoped per-row
   selectors.

   The IFM_Brief 20.8 grew three of these past what the static CSS assumed:
   assurance 2 -> 4 cards (2x2), problem 2 -> 5 cards (3 then 2), pillars 2 -> 3.
   The problem band uses a six-track row so both of its rows fill the width
   rather than leaving a hole beside the fifth card.                            */
.ggis-service-intro .et_pb_row.ggis-assure__grid,
.ggis-problem .et_pb_row.ggis-problem__grid,
.ggis-duo-section .et_pb_row.ggis-duo__grid {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 48rem) {
  .ggis-service-intro .et_pb_row.ggis-assure__grid,
  .ggis-problem .et_pb_row.ggis-problem__grid {
    --column-count: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
@media (min-width: 64rem) {
  .ggis-duo-section .et_pb_row.ggis-duo__grid {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    gap: 2.5rem;
  }
  .ggis-problem .et_pb_row.ggis-problem__grid {
    --column-count: 6;
    grid-template-columns: repeat(6, minmax(0, 1fr)) !important;
  }
  /* Divi wraps each column in its own element, so the span has to be applied to
     the column rather than to .ggis-problem__card inside it. */
  .ggis-problem .et_pb_row.ggis-problem__grid > .et_pb_column {
    grid-column: span 2;
  }
  .ggis-problem .et_pb_row.ggis-problem__grid > .et_pb_column:nth-child(4),
  .ggis-problem .et_pb_row.ggis-problem__grid > .et_pb_column:nth-child(5) {
    grid-column: span 3;
  }
}

/* --- IFM impact strip (the three stats under the USP columns) ----------------
   In the static build .ggis-impact is a div INSIDE .ggis-container: its own
   border-top hairline stops at the container inset, and its 3rem padding-top
   plus 4.5rem margin-top set the rhythm above the stats. The port emits it as
   a top-level Divi row, where (a) the global row rule strips padding-top, so
   the stats hug the line, and (b) a border-top spans the row's full
   border-box - INCLUDING the responsive side gutters - so the hairline ran
   viewport-wide. Fix: restore the spacing, drop the real border, and draw the
   hairline as an absolutely positioned pseudo-element inset by the same
   responsive gutters the row already carries.

   Specificity note: the global killer above is
   `.et_pb_section[class*="ggis-"] .et_pb_row:not(.et_pb_row_nested)` =
   (0,4,1) with !important, which outranks a plain three-class selector. The
   rules below mirror that shape to tie it, and win on source order.      */
.et_pb_section[class*="ggis-"] .et_pb_row.ggis-impact {
  position: relative;
  margin-top: 4.5rem !important;
  padding-top: 3rem !important;
  border-top: none;
}
.et_pb_section[class*="ggis-"] .et_pb_row.ggis-impact::before {
  content: "";
  position: absolute;
  top: 0;
  left: 1.5rem;
  right: 1.5rem;
  height: 1px;
  background: var(--ggis-line, rgba(23, 27, 22, 0.16));
}
@media (min-width: 48rem) {
  .et_pb_section[class*="ggis-"] .et_pb_row.ggis-impact::before { left: 2.5rem; right: 2.5rem; }
}
@media (min-width: 80rem) {
  .et_pb_section[class*="ggis-"] .et_pb_row.ggis-impact::before { left: 4rem; right: 4rem; }
}
@media (min-width: 96rem) {
  .et_pb_section[class*="ggis-"] .et_pb_row.ggis-impact::before { left: 6rem; right: 6rem; }
}

/* --- CMS grids: hard override -------------------------------------------------
   Same --column-count mechanism as the Landscape and IFM blocks above.
   .ggis-usp is the IFM page's USP band (the CMS page's equivalent section
   carries ggis-cms-intro); both share the .ggis-usp__grid row class.        */
.ggis-cms-intro .et_pb_row.ggis-usp__grid,
.ggis-usp .et_pb_row.ggis-usp__grid,
.ggis-cms-control .et_pb_row.ggis-cards,
.ggis-steps-section .et_pb_row.ggis-steps-layout,
.ggis-cms-queue .et_pb_row.ggis-bento__grid,
.ggis-cms-telemetry .et_pb_row.ggis-feature-highlights,
.ggis-values .et_pb_row.ggis-values__grid {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 48rem) {
  .ggis-cms-control .et_pb_row.ggis-cards {
    --column-count: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  .ggis-cms-queue .et_pb_row.ggis-bento__grid,
  .ggis-cms-telemetry .et_pb_row.ggis-feature-highlights {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
}
@media (min-width: 64rem) {
  .ggis-cms-intro .et_pb_row.ggis-usp__grid,
  .ggis-usp .et_pb_row.ggis-usp__grid {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
  .ggis-values .et_pb_row.ggis-values__grid {
    --column-count: 2;
    grid-template-columns: 0.9fr 1.1fr !important;
  }
}

/* The bento widget is a transparent SVG sitting on the card's tinted panel, so
   the Divi Image module must not add a wrapper background or its own spacing. */
.ggis-cms-queue .et_pb_module.ggis-bento__widget,
.ggis-cms-queue .et_pb_module.ggis-bento__widget .et_pb_image_wrap { display: block; width: 100%; }
.ggis-cms-queue .et_pb_module.ggis-bento__widget img { width: 100%; height: 100%; object-fit: cover; }

/* Before/after figure: the composite already carries both frames whole, so the
   Divi Image module must not be cropped or scaled by parallax here. */
.ggis-service-intro .et_pb_column.ggis-figure--dual { position: relative; }
.ggis-service-intro .et_pb_column.ggis-figure--dual .et_pb_module { margin-bottom: 0 !important; }

/* --- Natively-rebuilt grids (Smart Dashboard + AI Attendance) -----------------
   These blocks carry no inline SVG, so they are real Divi columns rather than a
   Code module - which is the point of the port: the client edits them in the
   Builder. That means Divi's --column-count has to be set for each, exactly as
   for the Landscape / IFM / CMS grids above.                                   */
.ggis-antifraud .et_pb_row.ggis-cards,
.ggis-tenant-section .et_pb_row.ggis-cards,
.ggis-why .et_pb_row.ggis-cards,
.ggis-features-section .et_pb_row.ggis-feature-highlights,
.ggis-modules-section .et_pb_row.ggis-module {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 48rem) {
  .ggis-antifraud .et_pb_row.ggis-cards--two {
    --column-count: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  .ggis-features-section .et_pb_row.ggis-feature-highlights {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
}
@media (min-width: 64rem) {
  .ggis-tenant-section .et_pb_row.ggis-cards--three,
  .ggis-why .et_pb_row.ggis-cards--three {
    --column-count: 3;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
  }
  /* Each dashboard module is its own row: screenshot beside the numbered list.
     Even modules mirror, matching .ggis-module:nth-child(even) in ggis.css. */
  .ggis-modules-section .et_pb_row.ggis-module {
    --column-count: 2;
    grid-template-columns: 1.1fr 0.9fr !important;
    align-items: center;
  }
}

/* --- Icon-split native blocks -------------------------------------------------
   Every list that used to travel as one Code module is now real Divi rows and
   columns, with only the inline <svg> left in a Code module. Divi needs its
   --column-count set for each, and the item rows are NESTED rows, which manage
   their own padding - hence :not(.et_pb_row_nested) on the general row rules
   elsewhere in this file.                                                      */

/* Industries: 1 / 2 / 4 across, matching ggis.css */
.et_pb_section[class*="ggis-"] .et_pb_row.ggis-sectors {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 48rem) {
  .et_pb_section[class*="ggis-"] .et_pb_row.ggis-sectors {
    --column-count: 2;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    column-gap: 3rem;
  }
}
@media (min-width: 64rem) {
  .et_pb_section[class*="ggis-"] .et_pb_row.ggis-sectors {
    --column-count: 4;
    grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
    column-gap: 2.5rem;
  }
}

/* Step / feature / value items are ONE Text module each (v1.0 pattern), so the
   .ggis-step / .ggis-feature-row / .ggis-values__row grids in ggis.css apply to
   the div inside the module and need no Divi override. Only the offer list is a
   real Divi grid row. */
.ggis-offer .et_pb_row.ggis-offer__list {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}

/* Offer items: each is a real Divi COLUMN (not an <li>) whose single Text
   module holds the check + label as INLINE siblings inside one <p>
   (WordPress wrapped them: <p><svg class="ggis-offer__mark">...</svg><span>Label</span></p>).
   ggis.css sets `svg { display: block }`, so the block-level check drops onto
   its own line above the label. Flex the paragraph itself: the svg becomes a
   flex child beside the span, restoring the design's rows-as-index. The
   hairline + row padding still come from ggis.css .ggis-offer__item, which
   rides on the column. */
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-offer__item .et_pb_module {
  margin-bottom: 0 !important;
}
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-offer__item .et_pb_text_inner > p {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-offer__item .et_pb_text_inner > p > svg {
  display: block;
  flex-shrink: 0;
  margin: 0;
}
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-offer__item .et_pb_text_inner > p > span {
  display: block;
}

/* Steps band: figure beside the step list.
   align-items must be STRETCH here, not start: at >=64rem the figure column's
   4:5 ratio is released (the rule above) so the photo tracks the step list's
   height - with `start` the column has no height source at all and collapses
   to 0px, which hid the workflow image entirely on the live Landscape page.
   The figure column itself gets height:100% because Divi columns are wrappers
   whose height:100% chain (column > .et_pb_image > .et_pb_image_wrap) needs
   every link filled once the ratio is gone. */
.ggis-steps-section .et_pb_row.ggis-steps-layout {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 64rem) {
  .ggis-steps-section .et_pb_row.ggis-steps-layout {
    --column-count: 2;
    grid-template-columns: 0.55fr 1fr !important;
    align-items: stretch !important;
  }
  .ggis-steps-section .et_pb_row.ggis-steps-layout > .et_pb_column.ggis-figure {
    height: 100%;
  }
  .ggis-steps-section .et_pb_row.ggis-steps-layout > .et_pb_column.ggis-figure > .et_pb_image {
    height: 100%;
  }
}

/* Multi-tenant diagram (AI Attendance #architecture). The diagram is ONE Text
   module per the reviewed v1.0 layout: .ggis-tenant is a flex column (console
   box, 1px stem, client grid) and only renders as a diagram when its children
   share that wrapper. Two Divi conflicts to clear:
   1. Divi wraps module content in .et_pb_text_inner; the flex must apply to the
      .ggis-tenant div itself, which is fine (it is a plain child), but Divi's
      text module adds its own font-size/line-height inheritance - harmless.
   2. Divi's global `p { padding-bottom }` would pad every promoted <p>
      (serials, eyebrows, labels) inside the diagram; the :where() p-reset near
      the top of this file already zeroes it. The stem is an empty div - Divi
      does not touch it. Only fix needed: the diagram's Text module must not
      inherit Divi's default paragraph margins (ggis.css sets element margins,
      not Divi's 1em padding). */
.ggis-tenant-section .et_pb_text_inner > .ggis-tenant { display: flex; }
.ggis-tenant-section .ggis-tenant p { margin: 0; }
.ggis-tenant-section .ggis-tenant .ggis-tenant__client .ggis-tenant__client-name { margin-top: 0.35rem; }
.ggis-tenant-section .ggis-tenant .ggis-tenant__client .ggis-tenant__client-note { margin-top: 0.15rem; }
.ggis-tenant-section .ggis-tenant .ggis-tenant__title { margin-top: 0.35rem; }

/* Dashboard modules alternate by CLASS in the static build, not by position -
   .ggis-module--flip flips the figure to the right. The class rides through on
   the row, so the flip targets the figure COLUMN here. */
.ggis-modules-section .et_pb_row.ggis-module--flip > .et_pb_column.ggis-module__figure { order: 2; }


/* --- Fixes from the first live import ---------------------------------------- */

/* 1. Sector rows: the icon belongs to the LEFT of the name. .ggis-sector is
   display:flex in ggis.css, but in Divi that class lands on the COLUMN, whose
   only child is the Text module - so the icon and name stacked inside it. Push
   the flex down to the module's inner wrapper, where the two actually live.
   Row-gap goes to 0: the items separate with their own bottom hairline, and
   Divi's default gap was doubling the spacing between the two rows of four. */
.et_pb_section[class*="ggis-"] .et_pb_row.ggis-sectors { row-gap: 0 !important; }
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-sector > .et_pb_text { width: 100%; margin-bottom: 0 !important; }
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-sector .et_pb_text_inner {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.et_pb_section[class*="ggis-"] .et_pb_column.ggis-sector .ggis-sector__name { margin: 0; }

/* 2. Steps figure: the ggis-figure classes now sit on the Image MODULE rather
   than the column, so the aspect ratio applies to a box that actually contains
   the <img>. Divi wraps the image in a <span>, which has no height of its own -
   without these the picture collapsed to a thin strip. */
.ggis-steps-section .et_pb_image.ggis-figure { display: block; width: 100%; }
.ggis-steps-section .et_pb_image.ggis-figure .et_pb_image_wrap {
  display: block;
  width: 100%;
  height: 100%;
}
.ggis-steps-section .et_pb_image.ggis-figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 3. Live Demo: a real two-column row now, preview on the right. */
.ggis-demo .et_pb_row.ggis-demo__grid {
  --column-count: 1;
  grid-template-columns: 1fr !important;
}
@media (min-width: 64rem) {
  .ggis-demo .et_pb_row.ggis-demo__grid {
    --column-count: 2;
    grid-template-columns: 0.9fr 1.1fr !important;
    gap: 5rem;
    align-items: center;
  }
}
.ggis-demo .et_pb_column.ggis-demo__previewcell .et_pb_text_inner > .ggis-demo__preview { display: block; }
