/* ══════════════════════════════════════════════════════════════════════
   GCX — shared site rules
   Added 8 Sep 2026 as gcx-mobile.css; renamed 9 Sep when it grew a
   cross-cutting block. Two parts: site-wide fixes first, then the mobile
   simplification.

   The premise: the buyer decides on desktop. Mobile is a shallow dive —
   establish what GCX does, show proof, offer a way to make contact. So
   everything that *argues in depth* is either dropped or put behind a tap,
   while everything that *orients* stays.

   Measured before this file existed, at 390x844:
     homepage       14,098px  (16.9 screens of scrolling)
     /solutions/dash 11,520px (13.6 screens)
     /solutions/best-energy 8,596px (10.2 screens)

   Every rule lives inside a max-width query, so desktop is untouched.
   Loaded from every page via <link>, deliberately NOT inlined — the site
   already carries 48 shadow copies of the nav CSS and that lesson was
   expensive. One file, one source of truth.

   The "show all" toggles are driven by gcx-includes.js (mobileCollapse).
   ══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════
   SITE-WIDE
   ══════════════════════════════════════════════════════════════════════ */

/* Long testimonials were a single undifferentiated block of italic type that
   readers skipped. The opening sentence is now the hook — larger and bold — and
   the supporting detail steps back. Sizes are in `em` so each quote scales from
   whatever its own page sets, and no page defines these classes, so there is no
   shadow-CSS fight. Mark up a quote as
   <span class="q-lead">First sentence.</span><span class="q-rest">The rest.</span> */
.q-lead {
  display: block;
  font-size: 1.22em;
  font-weight: 700;
  line-height: 1.34;
  letter-spacing: -0.01em;
  margin-bottom: 0.5em;
}
.q-rest {
  display: block;
  font-size: 0.82em;
  font-weight: 400;
  line-height: 1.7;
  opacity: 0.82;
}
@media (max-width: 767px) {
  .q-lead { font-size: 1.15em; }
  .q-rest { font-size: 0.85em; }
}

/* Every page declares `color-scheme: dark` so Safari paints a dark canvas
   during navigation instead of a white one. That also flips the UA styling of
   form controls, which are already styled light by hand — so the controls opt
   back out. Without this the contact form's select dropdown opens dark and
   Safari autofills dark text onto a dark field. */
input, select, textarea {
  color-scheme: light;
}

/* Inline links inside body prose had no rule anywhere, so they fell back to
   the browser default — #0000EE unvisited, #551A8B once visited. On the dark
   panels that is effectively illegible, and it looked like a 1996 hyperlink.
   Scoped to `p a` so the button links in the same containers are untouched.
   Uses the page's own accent where one is defined, with a brand fallback. */
.adv-overview-left p a,
.adv-overview p a,
.adv-journey p a,
.adv-video-more a {
  color: var(--cyan, #94D5D8);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  transition: color 0.15s, border-bottom-color 0.15s;
}
.adv-overview-left p a:hover,
.adv-overview p a:hover,
.adv-journey p a:hover,
.adv-video-more a:hover { color: #fff; border-bottom-color: #fff; }
/* The trust-bar logo strip is a marquee: 15 logos, nowrap, ~3,071px wide by
   design. Nothing was clipping it, so the whole document scrolled sideways on
   any viewport narrower than the strip. Clip at the wrapper, not the strip. */
.trust-bar, .trust-bar-outer, .logo-strip-wrap { overflow: hidden; }

/* ── Featured-article band ─────────────────────────────────────────────────
   A promo strip for a single flagship piece, reused across several pages. It
   borrows the shape of .adv-midcta (the DASH pages' mid-page CTA) so it reads as
   native, but carries its own colours rather than inheriting per-page ones —
   those differ between the dark advisory pages and the lighter homepage, and a
   band that changes appearance page to page looks like a mistake.

   Markup lives in each page so the link is a real crawlable <a>; only the
   styling is shared here, so a change to the look is a single edit. */
.gcx-feature-band {
  background: linear-gradient(115deg, #1B1D21 0%, #22262E 55%, #1B2A33 100%);
  border-top: 1px solid rgba(148,213,216,0.12);
  border-bottom: 1px solid rgba(148,213,216,0.12);
  padding: 48px;
}
.gcx-feature-inner {
  max-width: 1200px; margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 36px; flex-wrap: wrap;
}
.gcx-feature-copy { flex: 1 1 460px; min-width: 0; }
.gcx-feature-eyebrow {
  font-family: 'Montserrat', sans-serif; font-size: 11px; font-weight: 700;
  letter-spacing: 2.2px; text-transform: uppercase;
  color: #4FD3E8; margin: 0 0 12px;
  display: inline-flex; align-items: center; gap: 10px;
}
.gcx-feature-eyebrow::before {
  content: ''; width: 26px; height: 2px; background: #4FD3E8; flex: none;
}
.gcx-feature-band h3 {
  font-family: 'Montserrat', sans-serif; font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 300; line-height: 1.22; color: #fff; margin: 0 0 12px;
}
.gcx-feature-band h3 strong { font-weight: 800; color: #94D5D8; }
.gcx-feature-sub {
  font-size: 15px; line-height: 1.65; color: rgba(255,255,255,0.72);
  margin: 0; max-width: 620px;
}
.gcx-feature-cta {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 9px;
  padding: 15px 30px; border-radius: 9px;
  background: #1078BE; color: #fff; text-decoration: none;
  font-family: 'Montserrat', sans-serif; font-size: 14px; font-weight: 700;
  letter-spacing: 0.3px; white-space: nowrap;
  transition: background 0.2s, transform 0.2s;
}
.gcx-feature-cta:hover { background: #0d68a8; transform: translateY(-2px); }
.gcx-feature-cta:focus-visible { outline: 3px solid #94D5D8; outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .gcx-feature-cta, .gcx-feature-cta:hover { transition: none; transform: none; }
}
@media (max-width: 767px) {
  .gcx-feature-band { padding: 36px 20px !important; }
  .gcx-feature-inner { flex-direction: column; align-items: flex-start; gap: 22px; }
  /* flex-basis governs the MAIN axis, so the 460px basis above becomes a 460px
     HEIGHT the moment this container turns into a column — the copy block gets a
     460px box for ~150px of text and the button drops far below it. Same trap as
     .adv-midcta-copy on the DASH pages. */
  .gcx-feature-copy { flex: 0 0 auto; }
  .gcx-feature-cta { width: 100%; justify-content: center; }
}

/* ── Read more on long overview prose ──────────────────────────────────
   The partner and product overviews run to three or four body paragraphs —
   1,300 characters on iThemba Kuluntu — which is a wall of text before a
   visitor has decided they care. Paragraphs after the first are collapsed
   behind a toggle on desktop and mobile alike.

   Progressive enhancement: gcx-includes.js adds .gcx-rm and the button. With
   JS unavailable nothing is hidden, so the copy is always in the document for
   readers and for crawlers — the hidden paragraphs stay in the DOM either way,
   which keeps this out of cloaking territory. */
.gcx-rm-hidden { display: none; }
.gcx-rm-open .gcx-rm-hidden { display: block; }
.gcx-rm-btn {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 2px 0 0; padding: 0; border: 0; background: none; cursor: pointer;
  font-family: 'Montserrat', sans-serif; font-size: 13px; font-weight: 700;
  letter-spacing: 0.4px; line-height: 1.7;
  color: var(--cyan, #94D5D8);
  border-bottom: 1px solid currentColor;
  transition: opacity 0.15s;
}
.gcx-rm-btn:hover { opacity: 0.7; }
.gcx-rm-btn:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.gcx-rm-btn::after {
  content: '\2193'; font-size: 12px; transition: transform 0.2s ease;
}
.gcx-rm-btn[aria-expanded="true"]::after { transform: rotate(180deg); }

/* Counter animation rewrites the digits ~60x a second. With proportional
   figures each repaint is a different width, so a centred number visibly
   jitters. Tabular figures make every digit the same width. */
.stat-number { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }


/* ══════════════════════════════════════════════════════════════════════
   MOBILE
   ══════════════════════════════════════════════════════════════════════ */

@media (max-width: 767px) {

  /* ── 1. Standards carousel ──────────────────────────────────────────
     17-49 pills on an infinite marquee. On a desktop skim it reads as
     credibility furniture; on a phone it is an animating strip that costs
     battery, cannot be read at speed, and pushes the real content down.
     Appears on 12 pages. */
  .adv-standards { display: none !important; }


  /* ── 2. ICP cards -> compact list ───────────────────────────────────
     2,491px on the homepage for four tiles that are not clickable yet.
     Keeps the names and one line each; drops the icon and driver chrome. */
  .icp-grid { grid-template-columns: 1fr !important; gap: 0 !important; }
  .icp-card {
    padding: 16px 0 !important; border: none !important; border-radius: 0 !important;
    border-bottom: 1px solid rgba(148,213,216,0.14) !important; background: none !important;
  }
  .icp-card:last-of-type { border-bottom: none !important; }
  .icp-icon, .icp-driver, .icp-type { display: none !important; }
  .icp-name { margin-bottom: 4px !important; }
  .icp-desc {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; margin-bottom: 0 !important;
  }


  /* ── 3 + 4. Long block sections behind a tap ────────────────────────
     .adv-phases runs six blocks (~1,800px stacked); .adv-pkg-grid runs
     three cards with four bullets each (~1,800px). Both show a shortened
     set until the reader asks for the rest. gcx-includes.js adds the
     button and flips .mob-open. */
  .adv-phases:not(.mob-open) > .adv-phase:nth-child(n+4) { display: none; }
  .adv-pkg-grid:not(.mob-open) > .adv-pkg:nth-child(n+2) { display: none; }

  .mob-more {
    display: block; width: 100%; margin: 18px 0 0;
    padding: 13px 18px; border-radius: 8px; cursor: pointer;
    font-family: 'Montserrat', sans-serif; font-size: 12px; font-weight: 700;
    letter-spacing: 0.6px; text-transform: uppercase;
    background: transparent; border: 1px solid rgba(148,213,216,0.35);
    color: #94D5D8; -webkit-appearance: none; appearance: none;
  }
  .mob-more:active { background: rgba(148,213,216,0.1); }
  /* On the light-background sections the cyan-on-white would be weak. */
  .adv-journey .mob-more { border-color: rgba(13,40,71,0.25); color: #1078BE; }


  /* ── 5. Stats: five counters -> three ───────────────────────────────
     Animated counters are a desktop delight. Three carry the same point
     and save a screenful. */
  .stats-inner { grid-template-columns: 1fr 1fr !important; gap: 12px !important; }
  .stat-item:nth-child(n+4) { display: none !important; }
  .stat-item { padding: 24px 12px !important; }
  .stat-number { font-size: 30px !important; }


  /* ── 6. Discover: one feed, not three ───────────────────────────────
     1,895px of podcast + webinars + articles. Mobile keeps the two most
     recent cards and the link through to the full page. */
  .discover-grid { grid-template-columns: 1fr !important; }
  .discover-card:nth-child(n+3) { display: none !important; }
  /* The card sets aspect-ratio:16/10 with no width, so capping the HEIGHT at
     150px made the browser solve for width instead: the thumbnail came out
     240px wide inside a 335px card, leaving a dark strip down the right of
     every card. Constrain the ratio, not the height, and it fills. */
  .discover-thumb { aspect-ratio: 16 / 9 !important; width: 100% !important; }


  /* ── 7. Solutions cards ─────────────────────────────────────────────
     After the cuts above this became the tallest block on the homepage at
     2,596px across seven cards. Descriptions clamp to two lines (the full
     text is on the page each card links to) and the partner tier — already
     the peripheral one — shows two until asked. */
  .solution-card { padding: 22px 20px !important; }
  .sol-desc {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; margin-bottom: 14px !important;
  }
  .section-icon { width: 32px !important; height: 32px !important; margin-bottom: 12px !important; }
  .partner-grid:not(.mob-open) > .solution-card:nth-child(n+3) { display: none; }
  .partner-solutions { margin-top: 34px !important; padding-top: 28px !important; }


  /* ── Trim the remaining desktop-scale padding ───────────────────────
     Section padding tuned for a 1440px canvas reads as dead space on a
     390px one. */
  .adv-overview, .adv-journey, .adv-packages, .adv-cta,
  .stats, .icps, .solutions, .discover, .africa, .services-summary {
    padding-top: 52px !important; padding-bottom: 52px !important;
  }
  /* ── 8. Horizontal overflow guard ───────────────────────────────────
     Belt and braces behind the marquee clip above: nothing should ever let
     the document scroll sideways on a phone. */
  html, body { overflow-x: hidden; max-width: 100%; }

  /* ── 9. Consistent section rhythm ───────────────────────────────────
     The first pass enumerated section classes and so missed .case-feature
     and .maturity (100px) and .adv-video (60px), which is what produced the
     uneven gaps. Every section now gets the same rhythm, with the heroes and
     the full-bleed image break opted out because their spacing is structural. */
  section, .brand-video, .solutions {
    padding-top: 40px !important; padding-bottom: 40px !important;
  }
  /* Two stacked sections contribute both paddings, so 52px each read as a 104px
     void between related blocks — the gap under the Brent Shone video on About
     was exactly that. 40px gives 80px between sections, which still separates
     them without looking like something failed to load. */
  /* A section with no class of its own is missed by every page-level mobile
     rule, so the About closing CTA kept its desktop 48px side gutter while
     everything around it sat at 20px. */
  section:not([class]) { padding-left: 20px !important; padding-right: 20px !important; }
  .hero, .adv-hero, .journey-break, .trust-bar-outer {
    padding-bottom: 0 !important;
  }
  /* The nav is position:fixed and 80px tall on a phone, so zeroing the hero's
     top padding tucked the eyebrow and the first headline line underneath it
     (measured: eyebrow at y=8 on /solutions/training). Heroes sit at the top of
     the document and have to clear it; the two mid-page bands do not. */
  .hero, .adv-hero, .about-hero, .cmp-hero, .legal-hero, .dc-hero { padding-top: 96px !important; }
  .journey-break, .trust-bar-outer { padding-top: 0 !important; }
  .adv-hero { padding-bottom: 44px !important; }
  .hero { min-height: 620px !important; }

  /* ── 10. ICPs are desktop-only ──────────────────────────────────────
     Four persona tiles that are not yet clickable. On a shallow dive they
     cost a screenful and lead nowhere. */
  .icps { display: none !important; }

  /* ── 11. Hero headline: let it wrap naturally ───────────────────────
     At 360 the word "Sustainability" alone measures 263px in 264px of usable
     width, so the homepage's baked-in breaks pushed the sentence onto three
     lines with "is a" stranded. Font trimmed to 38px to buy that margin back.

     The break suppression that used to live here was scoped to `.hero h1` and
     so hit 38 pages, not the one it was tuned for. A hidden <br> contributes no
     whitespace, so wherever the markup had no space around it two words fused:
     "Build your sustainabilityknowledge", "DatatecSustainability at Scale",
     "Two DecadesIn The Trenches" — 20 pages in all. It also removed breaks that
     were deliberate, collapsing a case-study title and its subtitle onto one
     run of text. It now applies only to the homepage headline, via an explicit
     class on that h1. Every other hero keeps the breaks its author wrote.
     If a new headline needs the same treatment, add the class — do not widen
     the selector. */
  /* 38px left "organisations." at 288px in 279px of usable width, and because
     the heading also carries overflow-wrap:break-word the browser broke the word
     — stranding the full stop alone on its own line. 36px brings the longest
     word on any hero (organisations. 273px, Sustainability 262px) inside the
     measure, so nothing has to break. */
  /* Heroes put their side padding in one of two places depending on the page:
     gcx-discover.html has none on .hero and 48px on .hero-inner, the case
     studies have 48px on .hero. Setting 20px on the inner alone therefore
     stacked on top of the outer 48px and left the Sunbird headline just 239px
     to work with — "Sustainability" needs 262px, so it broke mid-word.
     Put the gutter on the outer element and zero it on the inner, which gives
     every hero the same 20px regardless of which shape it uses. Vertical
     padding is left alone. */
  .hero, .adv-hero, .about-hero, .cmp-hero, .legal-hero, .dash-hero, .dc-hero {
    padding-left: 20px !important; padding-right: 20px !important;
  }
  .hero-inner, .adv-hero-inner, .about-hero-inner, .cmp-hero .inner, .legal-hero-inner,
  .hero-content, .dash-hero-content, .about-hero-left {
    padding-left: 0 !important; padding-right: 0 !important;
  }

  .hero h1 { text-wrap: normal; font-size: 36px !important; }
  /* Same failure one level down: the DASH section headings render at 40px, where
     "environmental" measures 313px and "sustainability" 287px against 279px of
     usable width, so both broke mid-word ("sustainabilit / y data"). 34px is the
     largest size that keeps the longest word on the DASH page intact. */
  .section-h2 { font-size: 34px !important; }
  .hero h1.h1-unbreak > br:first-of-type,
  .hero h1.h1-unbreak strong br { display: none; }
  .adv-hero-inner h1 { text-wrap: balance; }

  /* ── 11b. Client logo strip: a grid, not a marquee ──────────────────
     The strip is 3,071px of logos inside a 335px window on a phone — two and a
     half logos drifting past, on a 55-second cycle to get through all fifteen.
     Nobody waits that out, so 228px of screen bought almost nothing. Show a
     static 3x2 of the six best-known names instead: same reassurance, a third of
     the height, and no motion to sit through. The full set stays on desktop.
     (The duplicate second run of logos exists only to make the marquee loop
     seamlessly, so hiding everything past the sixth costs nothing here.)

     Every property here needs !important: this file is a <link> in <head>, and
     each page's own <style> block comes after it, so at equal specificity the
     page wins. Without it the marquee's gap:72px and padding-right:72px survived
     and squeezed the three columns to 39px — Truworths rendered four pixels tall.
     Sizing is width + object-fit rather than max-height, because the logos are
     normalised to a common height and so vary hugely in width (Netcare 100x80,
     Truworths 731x80); one cell box with contain handles both. */
  .logo-strip-viewport { -webkit-mask-image: none; mask-image: none; overflow: visible; }
  .logo-strip {
    animation: none !important;
    display: grid !important;
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    align-items: center;
    gap: 18px 12px !important;
    width: 100% !important;
    padding: 0 !important;
  }
  .logo-strip img {
    width: 100% !important;
    height: 30px !important;
    max-height: none !important;
    object-fit: contain;
    margin: 0 !important;
  }
  .logo-strip img:nth-child(n+7) { display: none !important; }
  /* The marquee needs two identical strips to loop seamlessly. With the animation
     off, the second one is dead weight sitting off the right edge of the flex
     viewport — 15 more image elements laid out for nothing. */
  .logo-strip-viewport .logo-strip + .logo-strip { display: none !important; }

  /* ── 11c. Grids that never collapsed ───────────────────────────────
     Measured at 375px: these stayed at their desktop column counts, so a card
     or a paragraph was trying to live in 74-140px. That is where the one-word-
     and one-letter-per-line wrapping came from. gcx-case-studies.html has no
     media queries at all, and the others simply never covered these selectors.

     !important throughout: this file is a <link> in <head> and each page's own
     <style> follows it, so at equal specificity the page wins.

       .testimonial-inner   2 cols -> the video column was 38px wide
       .cs-grid             3 cols at 74px   (case studies index)
       .related-grid        3 cols at 77px   (foot of 4 case studies)
       .webinar-grid        3 cols at 77px   (Discover)
       .youtube-recent      3 cols at 82px   (Discover)
       .plans-grid          2 cols at 124px  (DASH pricing cards)
       .challenges-grid     3 cols at 131px  (Sun International)
       .overview-inner      2 cols at 140px  (Sunbird, UCT)                    */
  .testimonial-inner,
  .cs-grid,
  .related-grid,
  .webinar-grid,
  .youtube-recent,
  .plans-grid,
  .challenges-grid,
  .overview-inner {
    grid-template-columns: 1fr !important;
    gap: 22px !important;
  }
  /* The DASH testimonial pairs a video with a pull quote; stacked, the 80px
     desktop gutter reads as a hole. */
  .testimonial-inner { gap: 26px !important; }

  /* ── 11d. Fixed-pixel columns and squeezed header rows ─────────────
     Three grids carried hard px tracks that are wider than the phone itself,
     so their content ran straight off the side:
       .podcast-layout   320px 1fr   (Discover)
       .youtube-layout   1fr 520px   (Discover)
       .hero-inner       1fr 200px   (the outreach article)
     And two header rows are display:flex with a heading beside a button and no
     wrap, which crushed the heading to ~82-99px: that is the "The / Future / Of"
     one-word-per-line wrapping, and the same row sits on six case studies. */
  .podcast-layout,
  .youtube-layout,
  .hero-inner {
    grid-template-columns: 1fr !important;
    gap: 24px !important;
  }
  .related-header,
  .webinar-header,
  .articles-head,
  .discover-header {
    flex-wrap: wrap !important;
    gap: 18px !important;
    align-items: flex-start !important;
  }
  .related-header > *,
  .webinar-header > *,
  .articles-head > *,
  .discover-header > * { min-width: 0; }

  /* Grid items default to min-width:auto, so a 1fr track refuses to shrink below
     its content's intrinsic minimum and the column blows past the viewport —
     .podcast-layout still measured 479px inside a 279px box after the track was
     set to 1fr. min-width:0 is the fix; without it the column count above does
     nothing on these. */
  .podcast-layout > *,
  .youtube-layout > *,
  .hero-inner > *,
  .what-dash-inner > *,
  .testimonial-inner > *,
  .overview-inner > *,
  .cs-grid > *,
  .related-grid > *,
  .webinar-grid > *,
  .youtube-recent > *,
  .plans-grid > *,
  .challenges-grid > * { min-width: 0 !important; }

  /* Case-study hero stats are a nowrap flex row of four: 566px of content in a
     279px box on Sunbird, so the last two sat off-screen entirely. */
  .hero-stats {
    flex-wrap: wrap !important;
    gap: 14px 20px !important;
  }
  .hero-stats > * { min-width: 0; }
  .detail-row { flex-wrap: wrap !important; }

  /* Podcast episode rows put the title beside a nowrap Spotify/YouTube button
     pair — 195px of unbreakable content that pushed the row 175px past the
     card. Stack them. */
  .episode-card { flex-wrap: wrap !important; gap: 12px !important; }
  .episode-meta { white-space: normal !important; flex-wrap: wrap !important; }
  .episode-card > * { min-width: 0; }

  /* Absolutely-positioned hero decoration on the case studies runs past the
     right edge of its own hero. Harmless-looking, but it is real page width. */
  .hero, .adv-hero, .about-hero, .cmp-hero, .legal-hero { overflow-x: hidden; }

  /* ── 11e. Mobile hero legibility ───────────────────────────────────
     The desktop scrims on these heroes are left-weighted, built for a
     copy-left / photograph-right composition. Rotate that to a portrait phone
     and the gradient runs almost vertically, so the bright part of the picture
     lands directly behind the eyebrow and the headline.

     Composited each hero's real background stack (photo + every gradient layer)
     and measured against the brightest pixel behind each string. Six were below
     AA and two were effectively invisible:

       /solutions/dash-pinnacle   eyebrow 1.00:1   h1 3.25:1
       /solutions/packtrac        eyebrow 1.03:1   h1 2.78:1
       /solutions/dash-ascent     eyebrow 1.40:1   h1 2.70:1
       /solutions/climate         eyebrow 2.37:1   h1 2.68:1
       /solutions                 eyebrow 2.44:1   h1 2.78:1
       /solutions/waste           eyebrow 3.59:1   h1 3.78:1

     A flat wash under the copy fixes all of them and leaves desktop untouched.
     The four partner heroes already cleared 9:1 because their scrims were
     rebuilt earlier; the wash costs them a little contrast on the photo and
     nothing on the type. */
  .adv-hero { position: relative; }
  .adv-hero::after {
    content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 1;
    background: linear-gradient(to bottom,
      rgba(20,22,26,0.84) 0%,
      rgba(20,22,26,0.76) 55%,
      rgba(20,22,26,0.70) 100%);
  }
  .adv-hero-inner { position: relative; z-index: 2; }
  /* An accent-coloured eyebrow cannot survive a photograph; the partner heroes
     already use white for exactly this reason. */
  .adv-hero-inner .eyebrow { color: #fff !important; }
  /* White at 60% over a photograph lands at ~4.2:1 at 18px on the ITL and UCT
     case studies — just under AA. The training hero hit the same wall. */
  .hero-sub { color: rgba(255,255,255,0.78) !important; }

  /* ── 11f. flex-basis in a column container sizes HEIGHT ────────────
     .adv-midcta-copy is flex:1 1 420px. In the desktop row that is a sensible
     width basis; the mobile rule flips the container to flex-direction:column,
     where flex-basis applies to the main axis — now the height. So a block
     holding 95px of text was handed a 420px box, leaving 325px of empty screen
     between the heading and the buttons on Ascent and Pinnacle. */
  .adv-midcta-copy { flex: 0 0 auto !important; }

  /* "A complete waste picture" pairs a bold label with a description in a flex
     row. Each label sizes to its own text, so the descriptions began at four
     different x positions in the same list (103px, 121px, 145px, 159px) and the
     two-line labels wrapped under themselves. There is no room for a label
     column at 375px — stack the pair. :has() scopes this to the label/description
     rows and leaves the plain bulleted variant of the same class alone; where it
     is unsupported the rule is simply ignored. */
  .adv-caps-list li:has(> strong):has(> span) {
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 2px !important;
  }

  /* ── 12. Stats: four, not three ─────────────────────────────────────
     Three in a 2-up grid leaves an orphan on the second row. Four fills it. */
  .stat-item:nth-child(n+4) { display: block !important; }
  .stat-item:nth-child(n+5) { display: none !important; }
  .stat-number { min-height: 34px; display: block; }

  /* ── 13. Footer link row ────────────────────────────────────────────
     `display:flex; gap:20px` with no wrap: four links plus gaps come to
     382px, so at 360 the row is centred wider than the screen and the first
     link sits at x=-11. Wrap it. */
  .footer-contact { flex-wrap: wrap; justify-content: center; gap: 10px 18px !important; }

  /* ── 14. The DASH page ──────────────────────────────────────────────
     Bespoke markup that none of the shared rules above reach, and it shipped
     with essentially no mobile CSS: a 680px-wide hero column, a 56px h1 and a
     two-column module grid, all inside a 360px viewport. Seventeen element
     types were spilling past the right edge. */
  .dash-hero {
    min-height: auto !important;
    padding: 112px 20px 52px !important;
    align-items: flex-start !important;
  }
  .dash-hero-left { max-width: 100% !important; }
  .dash-hero-left h1 { font-size: clamp(30px, 8.5vw, 38px) !important; }
  .dash-hero-tagline { font-size: 17px !important; }
  .dash-hero-ctas { width: 100%; }
  .dash-hero-ctas > a { flex: 1 1 100%; text-align: center; }

  /* Two-up grids that have no business being two-up on a phone. */
  .modules-grid, .hdc-metrics, .hdc-steps, .plan-grid, .platform-cards {
    grid-template-columns: 1fr !important;
    gap: 22px !important;
  }
  .mod-visual { padding: 16px !important; }
  .mod-visual-shot { padding: 10px !important; }
  .mod-tabs { flex-wrap: wrap; gap: 8px; }

  /* The caption sits over the video with a negative offset that lands at -5px. */
  .video-caption { margin-left: 0 !important; padding: 0 4px; }

  /* Anything that still insists on being wider than the screen. */
  .dash-hero-inner, .modules-grid, .plan-grid, .section-inner { max-width: 100% !important; }
  img, svg, video, iframe { max-width: 100%; height: auto; }

  /* Inline-styled four-column stat strip on the DASH page (no class of its
     own until now) plus the two-up "what DASH is" block. Both were forcing
     ~490px of columns into a 264px container. */
  .dash-inline-stats { grid-template-columns: 1fr 1fr !important; gap: 20px 14px !important; }
  .what-dash-inner { grid-template-columns: 1fr !important; gap: 28px !important; }
  .platform-cards { width: 100% !important; }

  /* Long words in display headings were pushing a few pixels past the edge. */
  h1, h2, h3, .section-h2, .section-title { overflow-wrap: break-word; }

  /* ── 15. The About page ─────────────────────────────────────────────
     The team grid was a single 320px column holding 20 cards at 435px each:
     9,135px, roughly two thirds of the whole page. Two-up with tighter cards
     brings it to about a third of that, which suits a shallow dive far better
     than ten screens of portraits. */
  .team-grid { grid-template-columns: 1fr 1fr !important; gap: 12px !important; }
  .team-card { padding: 14px !important; }
  .team-card img, .team-card .team-photo { border-radius: 10px; }
  .team-name { font-size: 14px !important; }
  .team-role { font-size: 11px !important; }

  /* Not the grid — nested desktop padding. .about-cta contributes 48px a side
     and .about-cta-inner another 80px, leaving ~104px of usable width at 360,
     into which a .cta-action with min-width:280px does not go. */
  .about-cta { padding: 52px 20px !important; }
  .about-cta-inner { grid-template-columns: 1fr !important; padding: 32px 22px !important; gap: 24px !important; }
  .cta-action { min-width: 0 !important; width: 100%; }

  /* Same pattern anywhere else a panel nests inside a padded section. */
  .maturity-inner, .case-inner, .adv-cta { padding-left: 20px !important; padding-right: 20px !important; }

}
