/* =============================================================================
   CGS — brand layer
   -----------------------------------------------------------------------------
   Loaded AFTER assets/css/main.css (the Roofer theme system). Everything
   CGS-specific lives here; main.css is never edited, so theme components keep
   behaving predictably and this file stays the whole diff.

   Colour tokens started eyeball-matched to the rendered logo — the supplied
   JPEG carries a colour profile that shifts its raw pixel values, so that
   was always a placeholder pending a vector. They are now additionally
   calibrated against Maersk.com's real, rendered palette (sampled live via
   computed styles, not screenshotted or guessed): a deep near-black navy
   for primary surfaces and buttons, a brighter sky-blue reserved for
   accents rather than fills, 4px button corners, and no warm accent at all.
   Two container-shipping brands converging on the same blue-and-navy,
   minimal-accent language independently is the industry's own validation
   of the direction CGS's logo already pointed in — this tunes toward that
   consensus, it does not copy Maersk's exact hex values.
   Still re-derive these properly when the client sends a vector logo.
   ========================================================================== */

:root {
  /* Brand — the logo's left-to-right gradient, light cyan into deep navy,
     tuned toward the deeper/cleaner navy-and-sky-blue direction validated by
     Maersk.com's real palette (rgb(0,36,61) navy, rgb(66,176,213) accent
     blue, rgb(0,115,171) link blue, sampled 2026-08-17). */
  --cgs-cyan-300:  #6FC6E9;
  --cgs-cyan-400:  #2E9FD6;   /* lightest point of the mark; accents, icons, focus rings */
  --cgs-teal-500:  #1E8CB8;   /* requested accent — top bar background, CTA card gradient */
  --cgs-blue-500:  #146B96;   /* links, active nav — was a brighter purple-blue, now a cleaner ocean blue */
  --cgs-blue-600:  #0F5378;
  --cgs-navy-700:  #0E3A56;   /* primary button hover */
  --cgs-navy-900:  #082238;   /* primary button fill, footer, top bar — deep, near-black navy */

  --cgs-gradient:  linear-gradient(100deg, var(--cgs-cyan-400) 0%, var(--cgs-navy-900) 100%);

  /* Neutrals */
  --cgs-ink:       #0E1726;   /* headings and body text */
  --cgs-slate:     #4A5568;   /* secondary text */
  --cgs-muted:     #64708A;   /* darkened from the original #7A869A — that value measured 3.7:1 on white, below WCAG AA's 4.5:1; this passes at ~5:1 */
  --cgs-line:      #E4E8EF;   /* hairlines, card borders */
  --cgs-surface:   #F5F8FC;   /* tinted section backgrounds */
  --cgs-white:     #FFFFFF;

  /* No warm accent. The amber token this used to hold was flagged
     provisional; Maersk's real site carries zero warm colour anywhere,
     which settles the question — an all-blue palette is the industry norm
     here, not a gap to fill. Anything that read var(--cgs-accent) now reads
     var(--cgs-cyan-400) instead. */

  /* Status */
  --cgs-success:   #1E9E6A;
  --cgs-danger:    #D64550;

  /* Type — Plus Jakarta Sans, as the Roofer build uses. One family, used
     everywhere on the site — no secondary/mono face. */
  --cgs-font: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* Easing. The built-in CSS keywords are too weak to read as intentional;
     these are the stronger variants. ease-in is deliberately absent: it
     delays the first frame, which is exactly when the eye is watching. */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* Rhythm */
  --cgs-radius:    4px;        /* near-square corners read as industrial — Maersk's own buttons use the same 4px */
  --cgs-shadow:       0 8px 24px rgba(8, 34, 56, 0.08);
  --cgs-shadow-lg:    0 16px 48px rgba(8, 34, 56, 0.14);
  --cgs-shadow-float: 0 30px 70px -24px rgba(8, 34, 56, .55); /* heavier lift for elements meant to read as overlapping/floating, e.g. the closing CTA card */
  --cgs-section-y: clamp(56px, 7vw, 104px);
  --cgs-cta-overlap: clamp(48px, 6vw, 88px); /* how far the CTA card dips into the footer below it */
}

/* --- Base ---------------------------------------------------------------- */

/* Keeps an #anchor target clear of the sticky header instead of landing
   underneath it. */
html { scroll-padding-top: 96px; }

body {
  font-family: var(--cgs-font);
  color: var(--cgs-ink);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--cgs-font);
  color: var(--cgs-ink);
  letter-spacing: -0.01em;
}

/* Home page only: tightened to the "Hyer" landing concept's editorial type
   system — closer line-height and tracking on headings so they read as a
   considered display cut, text-wrap: balance so multi-word headlines break
   evenly instead of leaving a widow, and a slightly closer line-height on
   body copy. Scoped to #main-content so the shared header and footer keep
   the rhythm every other page uses. */
body.page-home #main-content h1,
body.page-home #main-content h2,
body.page-home #main-content h3 {
  line-height: 1.08;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
body.page-home #main-content p {
  line-height: 1.65;
}

a { color: var(--cgs-blue-500); }
a:hover { color: var(--cgs-navy-700); }

/* Skip link — keyboard users land on it first, invisible until focused */
.cgs-skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 2000;
  padding: 12px 20px;
  background: var(--cgs-navy-900);
  color: #fff;
  text-decoration: none;
}
.cgs-skip-link:focus { left: 0; }

/* --- Buttons ------------------------------------------------------------- */

.cgs-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 15px 28px;
  border: none;
  border-radius: var(--cgs-radius);
  font-weight: 600;
  font-size: 15px;
  line-height: 1;
  white-space: nowrap;          /* a CTA that wraps to two lines is broken */
  text-decoration: none;
  /* Named properties, not `all`: `all` animates things you did not intend
     and costs layout work on every one of them. */
  transition: transform 160ms var(--ease-out),
              box-shadow 200ms var(--ease-out),
              background-color 200ms ease,
              border-color 200ms ease,
              color 200ms ease;
}
/* Press feedback. Without it the button gives no sign it heard the click. */
.cgs-btn:active { transform: scale(0.97); }
.cgs-btn i { transition: transform 200ms var(--ease-out); }
.cgs-btn:hover i { transform: translateX(3px); }

/* Primary fill is the deep navy, not the brighter blue — Maersk's own
   buttons work the same way (rgb(0,36,61) fill, the brighter accent blue
   never appears as a button fill anywhere on their site). Keeping the
   brighter --cgs-blue-500 for links and active states instead of buttons
   gives the page one confident "this is the action" colour rather than
   the mid-blue doing double duty as both a link colour and a button fill. */
.cgs-btn--primary {
  background: var(--cgs-navy-900);
  color: #fff;
  box-shadow: 0 8px 20px rgba(8, 34, 56, .28);
}
.cgs-btn--primary:hover {
  background: var(--cgs-navy-700);
  color: #fff;
  box-shadow: 0 12px 28px rgba(8, 34, 56, .36);
}

.cgs-btn--ghost {
  background: transparent;
  color: var(--cgs-navy-900);
  border: 1.5px solid var(--cgs-line);
}
.cgs-btn--ghost:hover { border-color: var(--cgs-blue-500); color: var(--cgs-blue-500); }

.cgs-btn--on-dark { background: #fff; color: var(--cgs-navy-900); }
.cgs-btn--on-dark:hover { background: var(--cgs-cyan-300); color: var(--cgs-navy-900); }

/* Outline on a dark ground. Needs its own border because a transparent
   button over navy has no readable edge. */
.cgs-btn--outline-light {
  background: transparent;
  color: #fff;
  border: 1.5px solid rgba(255, 255, 255, .38);
}
.cgs-btn--outline-light:hover {
  background: rgba(255, 255, 255, .1);
  border-color: #fff;
  color: #fff;
}

/* Hover lift only where there is a real pointer. On touch, :hover sticks
   after a tap and the element stays lifted. */
@media (hover: hover) and (pointer: fine) {
  .cgs-btn:hover { transform: translateY(-2px); }
  .cgs-btn:active { transform: translateY(-2px) scale(0.97); }
}

/* --- Section scaffolding ------------------------------------------------- */

.cgs-section       { padding-block: var(--cgs-section-y); }
.cgs-section--tint { background: var(--cgs-surface); }
.cgs-section--dark { background: var(--cgs-navy-900); color: #fff; }
.cgs-section--dark h1,
.cgs-section--dark h2,
.cgs-section--dark h3 { color: #fff; }

.cgs-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-eyebrow--on-dark { color: var(--cgs-cyan-300); }

/* --- Hero ---------------------------------------------------------------- */

/* Desktop: a flat 100dvh + cover, not the video's own aspect-ratio — locking
   the section to 16:9 guarantees zero cropping, but on any desktop window
   proportionally wider than 16:9 (a maximized 1920x1080-ish browser, once
   its chrome eats some height, easily lands here) that forces the section
   TALLER than the viewport to keep full width, pushing everything below it
   off-screen. 100dvh always matches the screen exactly — full width, cover
   filling the full height too, a little of the footage's own edges trimmed
   off wherever the window's aspect isn't exactly 16:9 — which is the
   tradeoff for a section that always fills the display. Tablet/mobile
   don't have that overflow risk (they're rarely wider-than-16:9), so they
   keep the video's own ratio below instead, for zero cropping there. */
.cgs-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* 100dvh minus the topbar+header actually sitting above it (--cgs-header-h,
     set in cgs.js), not a flat 100dvh — the header is sticky, not fixed, so
     it still consumes real space in normal flow at the top of the page.
     A flat 100dvh hero pushed the section's own bottom edge (and the sound
     toggle pinned to it) below the first fold, off-screen until scrolled. */
  min-height: calc(100dvh - var(--cgs-header-h, 130px));
  background: var(--cgs-navy-900);
  color: #fff;
  overflow: hidden;
}

.cgs-hero__media { position: absolute; inset: 0; }
.cgs-hero__media img,
.cgs-hero__media video {
  width: 100%;
  height: 100%;
}
.cgs-hero__media img {
  /* The plain-image background variant (settings.hero_media_type=image)
     has no embedded watermark to protect, so it stays a full-bleed crop
     like every other hero/banner photo on the site. */
  object-fit: cover;
  object-position: center;
}
.cgs-hero__media video {
  /* client, 2026-08-28 ("video is cut the rendered logo inside the video
     for all devices, I want video to show full"): cover was cropping the
     top or bottom of the 1920x1080 footage on any desktop viewport wider
     than 16:9 (nearly all of them — the hero box is ~100dvh tall, not
     16:9-shaped), which cut off the logo watermark baked into the frame.
     contain guarantees the whole frame is always visible on every device,
     letterboxed with .cgs-hero's own navy background rather than cropped —
     on tablet/mobile the section is already locked to the video's exact
     16:9 ratio below, so contain and cover render identically there (no
     bars, same as before). */
  object-fit: fill;
  object-position: center;
}

/* --- Hero carousel ------------------------------------------------------- */

.cgs-hero__swiper {
  position: relative;
  flex: 1 1 auto;
  width: 100%;
  min-height: inherit;
}
.cgs-hero__swiper .swiper-wrapper { align-items: stretch; }

.cgs-hero__slide {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Matches .cgs-hero's own min-height exactly. A percentage height here
     (100%) does not reliably resolve against .swiper-wrapper — Swiper's
     wrapper only gets a definite height once its content does, which is
     circular through a flex-grow ancestor — so the slide (and the image
     inside it) came up short of the hero's actual bottom edge, leaving a
     visible strip of the section's navy background below the photograph.
     Sizing both to the same calc() sidesteps the percentage chain. */
  min-height: calc(100dvh - var(--cgs-header-h, 130px));
  height: auto;
  overflow: hidden;
}

.cgs-hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* Tablet/mobile: the desktop clamp() above is sized for a wide window, so
   object-fit:cover was cropping the sides off the (16:9) footage on any
   narrower/taller viewport. Sizing the section to the video's own 16:9
   ratio instead means cover has nothing left to crop — the full width of
   the frame is always in view. Doesn't risk the desktop overflow problem
   (see the .cgs-hero comment above) since these viewports are essentially
   never wider-than-16:9 in the first place. .cgs-hero__slide's own
   min-height floor has to drop too, or its flex content would just force
   the section taller than the aspect-ratio again. */
@media (max-width: 991.98px) {
  .cgs-hero { min-height: 0; aspect-ratio: 16 / 9; }
  .cgs-hero__slide { min-height: 0; height: 100%; }
}

@media (max-width: 767.98px) {
  .cgs-hero__actions .cgs-btn { width: 100%; justify-content: center; }
}

/* Hero sound toggle — the one control a visitor gets over the background
   footage (it autoplays muted; browser policy leaves no other option).
   Circular pill/blur treatment, pinned to the corner. Both icons are
   always in the DOM; only opacity/scale swap on state, so the toggle
   never repaints layout. */
.cgs-hero__sound {
  position: absolute;
  z-index: 2;
  right: clamp(20px, 3vw, 32px);
  bottom: clamp(20px, 3vw, 32px);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  background: rgba(8, 20, 40, .38);
  border: 1px solid rgba(255, 255, 255, .24);
  backdrop-filter: blur(4px);
  color: #fff;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out), border-color 200ms var(--ease-out), transform 160ms var(--ease-out);
}
.cgs-hero__sound:hover,
.cgs-hero__sound:focus-visible {
  background: rgba(8, 20, 40, .6);
  border-color: var(--cgs-cyan-400);
}
.cgs-hero__sound:active { transform: scale(.94); }
.cgs-hero__sound i {
  grid-area: 1 / 1;
  font-size: 15px;
  transition: opacity 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.cgs-hero__sound .fa-volume-high { opacity: 0; transform: scale(.8); }
.cgs-hero__sound.is-unmuted .fa-volume-xmark { opacity: 0; transform: scale(.8); }
.cgs-hero__sound.is-unmuted .fa-volume-high { opacity: 1; transform: scale(1); color: var(--cgs-cyan-400); }

@media (max-width: 575.98px) {
  .cgs-hero__sound { width: 38px; height: 38px; }
  .cgs-hero__sound i { font-size: 13px; }
}

/* --- Credentials -----------------------------------------------------------
   Sits directly after the hero. Entity names, registration numbers and the
   UEN that used to sit in a left column here now live in the navbar logo
   lockup (includes/header.php) instead.
   2026-08-21 (client: "remove certification instead make it as badge with
   icons only"): the old full-page PDF-preview cards are retired in favor
   of a compact row of round badges — the real registrar seal artwork
   (assets/img/certificates/badge-*.png), not a screenshot of the PDF's
   first page. Each badge is still a real link: clicking it opens the
   actual PDF in a Magnific Popup lightbox instead of a new tab (client,
   earlier: "open pdf in popup") — init lives in includes/scripts.php,
   popup sizing overrides are the .cgs-pdf-popup rules right after this
   block. */
.cgs-credentials__head {
  max-width: 640px;
  margin: 0 0 clamp(28px, 3.5vw, 40px);
}
.cgs-credentials__head h2 {
  margin: 0;
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}

.cgs-credentials__badges {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(28px, 4vw, 56px);
}
.cgs-credentials__badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 128px;
  text-align: center;
  text-decoration: none;
  color: inherit;
  transition: transform 200ms var(--ease-out);
}
.cgs-credentials__badge:hover,
.cgs-credentials__badge:focus-visible {
  transform: translateY(-4px);
}
.cgs-credentials__badge-icon {
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  padding: 16px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--cgs-line);
  box-shadow: var(--cgs-shadow);
  overflow: hidden;
}
.cgs-credentials__badge-icon img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.cgs-credentials__meta {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--cgs-slate);
  line-height: 1.35;
}

@media (prefers-reduced-motion: reduce) {
  .cgs-credentials__badge { transition: none; }
}

/* Magnific Popup override for the certificate lightbox: the plugin's
   default .mfp-iframe-scaler assumes 16:9 video, which leaves a portrait
   A4 certificate letterboxed and tiny. mainClass: 'cgs-pdf-popup' (set in
   the init in includes/scripts.php) scopes these to just that popup. */
.cgs-pdf-popup .mfp-iframe-holder .mfp-content { max-width: 640px; }
.cgs-pdf-popup .mfp-iframe-scaler { padding-top: 137%; }
.cgs-pdf-popup .mfp-iframe-scaler iframe { background: #fff; }
@media (max-width: 700px) {
  .cgs-pdf-popup .mfp-iframe-holder .mfp-content { max-width: 92vw; }
}

/* --- Homepage video band (the brief's 20-second section) -----------------
   Inset in its own container and framed like a card, not full-bleed: the
   video floats over the section background instead of butting straight
   into the viewport edges. */

/* White section, not navy or a photo: the frame itself carries all the
   real imagery, so the empty space around it gets an abstract, not
   photographic, treatment — a faint technical dot-grid plus two soft
   colour fields in the corners. Decoration, not documentation, so it
   doesn't have to be a real asset. */
.cgs-video-band {
  position: relative;
  overflow: hidden;
  padding-block: clamp(40px, 5vw, 72px);
  background: #fff;
}
.cgs-video-band::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(var(--cgs-line) 1px, transparent 1px);
  background-size: 28px 28px;
  opacity: .6;
  pointer-events: none;
}
.cgs-video-band::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(380px circle at 94% -8%, rgba(46, 159, 214, .22), transparent 70%),
    radial-gradient(320px circle at -6% 108%, rgba(20, 107, 150, .16), transparent 70%);
  pointer-events: none;
}
.cgs-video-band > .container-fluid { position: relative; z-index: 1; }
/* Smaller and centred, not full-bleed: a plain video, no overlay copy or
   scrim needed on top of it, so the frame itself can just be modest. */
.cgs-video-band__frame {
  position: relative;
  max-width: 860px;
  margin-inline: auto;
  border-radius: var(--cgs-radius);
  overflow: hidden;
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-video-band__frame video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: contain;
}

/* --- Cards --------------------------------------------------------------- */

.cgs-card {
  height: 100%;
  background: #fff;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
  transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.cgs-card:hover {
  transform: translateY(-4px);
  border-color: transparent;
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-card__media { aspect-ratio: 16 / 10; overflow: hidden; }
.cgs-card__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .5s ease;
}
.cgs-card:hover .cgs-card__media img { transform: scale(1.05); }
.cgs-card__body { padding: 24px; }

/* --- Header / footer chrome --------------------------------------------- */

.cgs-topbar {
  background: var(--cgs-teal-500);
  color: rgba(255, 255, 255, .92);
  font-size: 14px;
}
.cgs-topbar a { color: rgba(255, 255, 255, .92); text-decoration: none; }
.cgs-topbar a:hover { color: #fff; }

.cgs-footer {
  position: relative;
  background: var(--cgs-navy-900);
  color: rgba(255, 255, 255, .72);
  font-size: 14.5px;
}
.cgs-footer h3 {
  margin: 0 0 18px;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.cgs-footer a { color: rgba(255, 255, 255, .72); text-decoration: none; transition: color .2s ease; }
.cgs-footer a:hover { color: var(--cgs-cyan-300); }

.cgs-footer__logo { margin-bottom: 6px; height: auto; max-width: 180px; }

/* Slogan, directly under the logo/wordmark. settings.tagline — editable
   from the admin like the rest of company identity, not hard-coded. */
.cgs-footer__tagline {
  margin: 0 0 14px;
  font-size: 14px;
  font-weight: 600;
  font-style: italic;
  color: var(--cgs-cyan-400);
}

/* Both registered entities — the footer's actual company-name lockup now
   that the separate wordmark title is gone. Rebuilt 2026-08-21 (client:
   "in footer change company name to like header") into the same 3-line
   shape as the header's .cgs-logo lockup: two equal-weight entity names,
   then the ISO statement as a smaller caption underneath — .cgs-logo__line
   and .cgs-logo__line--iso's proportions, just white-on-navy instead of
   navy-on-white and a size step up (client, earlier: "change footer
   company name in white and bigger") since this is the primary identity
   line here, not a small print-out under a bigger title. */
.cgs-footer__entities {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0 0 16px;
}
.cgs-footer__entity-name {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #fff;
}
.cgs-footer__entity-iso {
  margin: 4px 0 0;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--cgs-cyan-400);
}

.cgs-footer__blurb { margin: 0 0 16px; line-height: 1.75; max-width: 42ch; }

.cgs-footer__links,
.cgs-footer__contact,
.cgs-footer__socials { margin: 0; padding: 0; list-style: none; }

.cgs-footer__links li { margin-bottom: 11px; }

.cgs-footer__contact li {
  display: flex;
  gap: 11px;
  margin-bottom: 13px;
  line-height: 1.6;
}
.cgs-footer__contact i { padding-top: 4px; color: var(--cgs-cyan-400); font-size: 13px; }

.cgs-footer__socials { display: flex; gap: 10px; }
.cgs-footer__socials a {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font-size: 14px;
  transition: background-color .2s ease;
}
.cgs-footer__socials a:hover { background: var(--cgs-blue-500); color: #fff; }

.cgs-footer__bar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: space-between;
  padding: 22px 0;
  border-top: 1px solid rgba(255, 255, 255, .12);
  font-size: 13.5px;
}
.cgs-footer__bar p { margin: 0; }

/* --- Top info bar -------------------------------------------------------- */

.cgs-topbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 36px;
}

.cgs-topbar__contacts {
  display: flex;
  align-items: center;
  gap: 14px;
}
.cgs-topbar__contact {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}
/* Second contact item gets a divider, same treatment as the ISO badge's
   border-right on the other side of the bar. */
.cgs-topbar__contact + .cgs-topbar__contact {
  padding-left: 20px;
  border-left: 1px solid rgba(255, 255, 255, .28);
}
/* White, not --cgs-cyan-400: the mark's lightest accent all but disappears
   against this teal background — the two are too close in tone/luminance
   to read as a highlight here, even though the pairing works everywhere
   else in the palette. */
.cgs-topbar__contact i {
  color: #fff;
  font-size: 12px;
  transition: transform 160ms var(--ease-out);
}
.cgs-topbar__contact:hover i { transform: rotate(-12deg) scale(1.1); }

.cgs-topbar__right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.cgs-topbar__socials {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cgs-topbar__socials a {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  font-size: 13px;
  color: rgba(255, 255, 255, .78);
  transition: color 160ms var(--ease-out), background-color 160ms var(--ease-out);
}
.cgs-topbar__socials a:hover {
  color: #fff;
  background: rgba(255, 255, 255, .12);
}
.cgs-topbar__socials a:active { transform: scale(0.94); }

.cgs-topbar__login {
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .1);
  font-size: 12px;
  transition: background-color .2s ease;
}
.cgs-topbar__login:hover { background: var(--cgs-blue-500); }

/* --- Main navbar --------------------------------------------------------- */

.cgs-header {
  position: sticky;
  top: 0;
  z-index: 1020;
  background: #fff;
  border-bottom: 1px solid var(--cgs-line);
  transition: box-shadow .25s ease;
}
/* .is-stuck is toggled in cgs.js once the page scrolls past the top bar */
.cgs-header.is-stuck { box-shadow: 0 4px 20px rgba(10, 30, 92, .1); }

.cgs-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 116px; /* clears the 100px logo plus breathing room */
}

/* Logo — 2026-08-21 home page redesign (client: "the logo must be bigger.
   Do not write the UEN number in the top left corner; instead, write the
   company names and below company name our ISO 9001:2015 Certified").
   Now rendered from the transparent-background mark
   (assets/img/logo/cgs-mark.png, cropped from the client's supplied JPEG
   via background removal) instead of the old white-boxed JPEG, sized by
   height with width following its own aspect ratio rather than forced
   into a square box — the mark itself is a wide oval, not a square
   monogram. The two entity names stay (still real facts, not new ones),
   but their UEN/registration numbers are dropped from this lockup and the
   settings.iso_statement line takes that third row instead; the full
   entity+UEN detail still lives in the footer (includes/footer.php),
   unchanged. */
.cgs-logo {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  min-width: 0; /* lets the name+ISO lines wrap instead of forcing the burger off-screen on narrow viewports */
}
.cgs-logo img { height: 100px; width: auto; object-fit: contain; flex-shrink: 0; }
.cgs-logo__text { display: flex; flex-direction: column; gap: 2px; line-height: 1.3; min-width: 0; }
/* Both entity names read as one consistent format — same size, weight and
   color — rather than a heading/sub-heading hierarchy. */
.cgs-logo__line {
  font-size: clamp(13px, 1.3vw, 14.5px);
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--cgs-navy-900);
}
/* The ISO line reads as a certification caption under the identity, not a
   third equal-weight name — smaller, the brand's link-blue rather than
   navy, and a touch of tracking like the site's other credential badges
   (.cgs-footer__entity-iso, .cgs-eyebrow). */
.cgs-logo__line--iso {
  margin-top: 1px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}

.cgs-nav ul {
  display: flex;
  align-items: center;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cgs-nav li { position: relative; }
.cgs-nav > ul > li > a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 26px 9px;
  font-size: 15.5px;
  font-weight: 600;
  color: var(--cgs-ink);
  text-decoration: none;
  transition: color .2s ease;
}
.cgs-nav > ul > li > a::after {
  content: "";
  position: absolute;
  left: 9px;
  right: 9px;
  bottom: 0;
  height: 3px;
  background: var(--cgs-gradient);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .25s ease;
}
.cgs-nav > ul > li > a:hover,
.cgs-nav > ul > li > a.is-active { color: var(--cgs-blue-500); }
.cgs-nav > ul > li > a:hover::after,
.cgs-nav > ul > li > a.is-active::after { transform: scaleX(1); }
.cgs-nav > ul > li > a i { font-size: 11px; transition: transform .25s ease; }
.cgs-nav .has-dropdown:hover > a i { transform: rotate(180deg); }

/* Dropdown. Kept in the layout (not display:none) so it can transition,
   and hidden from assistive tech + pointer events until opened. */
.cgs-submenu {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 288px;
  padding: 10px 0 !important;
  background: #fff;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  box-shadow: var(--cgs-shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .22s ease, transform .22s ease, visibility .22s;
  flex-direction: column;
  align-items: stretch !important;
  gap: 0 !important;
}
.cgs-nav .has-dropdown:hover > .cgs-submenu,
.cgs-nav .has-dropdown:focus-within > .cgs-submenu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.cgs-submenu a {
  display: block;
  padding: 11px 22px;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--cgs-slate);
  text-decoration: none;
  border-left: 3px solid transparent;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
.cgs-submenu a:hover,
.cgs-submenu a.is-active {
  background: var(--cgs-surface);
  color: var(--cgs-blue-500);
  border-left-color: var(--cgs-cyan-400);
}

/* Header right-hand side */
.cgs-header__actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

.cgs-header__call {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
}
.cgs-header__call-icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-blue-500);
  font-size: 15px;
  transition: background-color .2s ease, color .2s ease;
}
.cgs-header__call:hover .cgs-header__call-icon {
  background: var(--cgs-blue-500);
  color: #fff;
}
.cgs-header__call-text { display: flex; flex-direction: column; line-height: 1.25; }
.cgs-header__call-text small { font-size: 11.5px; color: var(--cgs-muted); }
.cgs-header__call-text strong { font-size: 15px; color: var(--cgs-navy-900); }

.cgs-burger {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  background: #fff;
  color: var(--cgs-navy-900);
  font-size: 19px;
  cursor: pointer;
  transition: transform 160ms var(--ease-out), border-color 200ms ease;
}
.cgs-burger:active { transform: scale(0.94); }
.cgs-burger[aria-expanded="true"] { border-color: var(--cgs-navy-900); }
/* Icon swap: two glyphs stacked, CSS shows one based on aria-expanded — no
   classList mutation needed in JS, the button's own state drives it. */
.cgs-burger .cgs-burger__close { display: none; }
.cgs-burger[aria-expanded="true"] .cgs-burger__open  { display: none; }
.cgs-burger[aria-expanded="true"] .cgs-burger__close { display: block; }

@media (max-width: 575.98px) {
  .cgs-header__inner { min-height: 88px; }
  .cgs-logo { gap: 10px; }
  .cgs-logo img { height: 68px; }
  .cgs-logo__line { font-size: 11px; }
  .cgs-logo__line--iso { font-size: 10px; }
}

/* --- Mobile menu: dropdown, not a side panel -----------------------------
   Attached to the navbar and drops down from it — the same "menu opens
   where you triggered it" language as the desktop Services hover dropdown
   just above (.cgs-submenu), rather than a drawer that slides in from a
   screen edge and takes over the full viewport height. It is a child of
   .cgs-header (which is already position:sticky, so it is a positioning
   context) so `top: 100%` always lands exactly at the navbar's current
   bottom edge — correct whether the top info bar above it is showing or
   has scrolled away, with no JS height math needed. */

.cgs-mobile-panel {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 1015;
  max-height: min(80dvh, 640px);
  overflow-y: auto;
  background: #fff;
  border-bottom: 1px solid var(--cgs-line);
  box-shadow: var(--cgs-shadow-lg);
  transform-origin: top;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scaleY(0.98);
  pointer-events: none;
  transition: opacity 220ms var(--ease-out),
              transform 220ms var(--ease-out),
              visibility 220ms;
}
.cgs-mobile-panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scaleY(1);
  pointer-events: auto;
}

.cgs-mobile-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 24px;
  border-bottom: 1px solid var(--cgs-line);
}
.cgs-mobile-panel__head h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--cgs-navy-900);
}
.cgs-mobile-panel__close {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-navy-900);
  font-size: 14px;
  cursor: pointer;
  transition: background-color 160ms ease;
}
.cgs-mobile-panel__close:hover { background: var(--cgs-line); }

.cgs-mobile-panel__body { padding: 20px 24px 32px; }

/* Light scrim behind the panel, dimming the page rather than covering it —
   confirms the panel is a temporary overlay without a full-screen takeover.
   Decorative and pointer-transparent except for its own click-to-close. */
.cgs-mobile-scrim {
  position: fixed;
  inset: 0;
  z-index: 1010;
  background: rgba(8, 34, 56, .32);
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms ease, visibility 220ms;
}
.cgs-mobile-scrim.is-open { opacity: 1; visibility: visible; }

@media (min-width: 1200px) {
  .cgs-mobile-panel, .cgs-mobile-scrim { display: none; }
}

.cgs-mobile-nav { margin: 0 0 24px; padding: 0; list-style: none; }
.cgs-mobile-nav > li { border-bottom: 1px solid var(--cgs-line); }
.cgs-mobile-nav > li > a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 2px;
  font-size: 16px;
  font-weight: 600;
  color: var(--cgs-ink);
  text-decoration: none;
}
.cgs-mobile-nav > li > a.is-active { color: var(--cgs-blue-500); }
.cgs-mobile-nav__toggle i { font-size: 12px; transition: transform .25s ease; }
.cgs-mobile-nav__toggle[aria-expanded="true"] i { transform: rotate(180deg); }

.cgs-mobile-nav__sub {
  margin: 0 0 12px;
  padding: 0 0 0 14px;
  list-style: none;
  border-left: 2px solid var(--cgs-line);
}
.cgs-mobile-nav__sub a {
  display: block;
  padding: 10px 0;
  font-size: 14.5px;
  color: var(--cgs-slate);
  text-decoration: none;
}
.cgs-mobile-nav__sub a.is-active { color: var(--cgs-blue-500); font-weight: 600; }

.cgs-mobile-cta { display: flex; flex-direction: column; gap: 10px; }
.cgs-mobile-cta__email {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-top: 4px;
  font-size: 13.5px;
  color: var(--cgs-slate);
  text-decoration: none;
  word-break: break-all;
}

.cgs-mobile-foot {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--cgs-line);
}
.cgs-mobile-foot__addr {
  display: flex;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--cgs-slate);
}
.cgs-mobile-foot__addr i { color: var(--cgs-cyan-400); padding-top: 3px; }
.cgs-mobile-foot__iso { margin: 0 0 14px; font-size: 12.5px; color: var(--cgs-muted); }
.cgs-mobile-foot__socials {
  display: flex;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cgs-mobile-foot__socials a {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-navy-900);
  font-size: 14px;
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease;
}
.cgs-mobile-foot__socials a:hover { background: var(--cgs-blue-500); color: #fff; }

/* --- Floating contact stack --------------------------------------------- */

.cgs-float-stack {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 999;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.cgs-float-stack a {
  width: 52px; height: 52px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: #fff;
  font-size: 22px;
  box-shadow: var(--cgs-shadow);
}
.cgs-float-stack .is-whatsapp { background: #25D366; }
.cgs-float-stack .is-call     { background: var(--cgs-blue-500); }

/* --- Section heads ------------------------------------------------------- */

.cgs-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: clamp(32px, 4vw, 52px);
}
.cgs-section-head h2 {
  margin: 0;
  max-width: 20ch;
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.cgs-textlink {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  padding-bottom: 4px;
  font-size: 15px;
  font-weight: 600;
  color: var(--cgs-blue-500);
  text-decoration: none;
  border-bottom: 1.5px solid transparent;
  transition: border-color 200ms var(--ease-out);
}
.cgs-textlink:hover { border-bottom-color: currentColor; }
.cgs-textlink i { transition: transform 200ms var(--ease-out); }
.cgs-textlink:hover i { transform: translateX(3px); }

@media (max-width: 767.98px) {
  .cgs-section-head { flex-direction: column; align-items: flex-start; gap: 14px; }
}

/* --- Services swiper -------------------------------------------------------
   Each slide is one service's own 5-tile bento grid — a photo feature cell
   plus four info cells. Swiping moves between services; the grid shape
   itself never changes. */

.cgs-section-head__right { display: flex; align-items: center; gap: 20px; }

.cgs-services__arrows { display: flex; align-items: center; gap: 10px; }
.cgs-services__arrow {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  padding: 0;
  border: 1.5px solid var(--cgs-line);
  border-radius: 50%;
  background: transparent;
  color: var(--cgs-navy-900);
  font-size: 14px;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              color 200ms var(--ease-out),
              transform 160ms var(--ease-out);
}
.cgs-services__arrow:active { transform: scale(0.94); }
.cgs-services__arrow:disabled { opacity: .38; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .cgs-services__arrow:not(:disabled):hover {
    background: var(--cgs-navy-900);
    border-color: var(--cgs-navy-900);
    color: #fff;
  }
}

/* --- Services scroll-pin --------------------------------------------------
   .is-pinned is added by cgs.js only on desktop widths with motion allowed
   (never under prefers-reduced-motion, never on narrow viewports) — the
   section's own height becomes services-count x 58vh so scrolling through
   it holds .cgs-services-pin__sticky in place while each service crossfades
   in, then releases to the next section once the last one has shown. Was
   100vh per service; 58vh gets through the same five slides in noticeably
   less scrolling without making any one crossfade feel rushed. */
.cgs-services-pin.is-pinned { height: calc(var(--services-count, 1) * 58vh); }

.cgs-services-pin.is-pinned .cgs-services-pin__sticky {
  position: sticky;
  top: var(--cgs-header-h, 85px);
  height: calc(100dvh - var(--cgs-header-h, 85px));
  overflow: hidden;
  display: flex;
}
.cgs-services-pin.is-pinned .cgs-services-pin__sticky > .container-fluid {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
}
.cgs-services-pin.is-pinned .cgs-section-head,
.cgs-services-pin.is-pinned .cgs-services-pin__track { flex-shrink: 0; }

/* Default JS behaviour (no pin, no carousel — desktop with reduced motion
   only, now that the sub-992px case runs the swiper below instead): the
   arrows show/hide the active slide in normal block flow. Scoped off of
   :not(.swiper-initialized) so it steps aside the moment cgs.js turns the
   stage into a real carousel — Swiper needs every slide actually laid out
   to compute its own widths, and this display:none would zero them out.
   Without JS at all, neither rule applies (no .js class, no swiper either)
   and every service's grid stacks and shows at once. */
html.js [data-services-stage]:not(.swiper-initialized) [data-service-slide] { display: none; margin: 0; }
html.js [data-services-stage]:not(.swiper-initialized) [data-service-slide].is-active { display: grid; }

/* Pinned behaviour: every slide stays laid out, absolutely stacked on top
   of each other, and crossfades via opacity/transform as scroll progress
   (or the arrows) move the active index. The stage fills whatever space is
   left in the sticky viewport (flex: 1 1 auto) — stable to size against
   since .is-pinned only ever applies on desktop, where the grid's own
   height doesn't change between services. */
.cgs-services-pin.is-pinned .cgs-services-pin__stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}
.cgs-services-pin.is-pinned [data-service-slide] {
  display: grid;
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 420ms var(--ease-out), transform 420ms var(--ease-out);
  pointer-events: none;
}
.cgs-services-pin.is-pinned [data-service-slide].is-active {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* Progress line: only meaningful while pinned, since only then does
   scrolling itself carry a "how far through" position. */
.cgs-services-pin__track { display: none; }
.cgs-services-pin.is-pinned .cgs-services-pin__track {
  display: block;
  height: 3px;
  margin-top: 20px;
  border-radius: 2px;
  background: var(--cgs-line);
  overflow: hidden;
}
.cgs-services-pin__fill { display: block; height: 100%; width: 0%; background: var(--cgs-cyan-400); }

/* One 5-tile bento per slide: a photo feature cell plus four info cells
   filling the rest of a 4-col x 3-row grid. The info cells are sized
   asymmetrically — a wide description, a tall icon, two small stacked
   cells (CTA, index) — rather than four identical squares, so the grid
   reads as composed rather than a repeated unit. */
.cgs-service-bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, minmax(168px, 1fr));
  gap: 16px;
  height: 100%;
}

.cgs-service-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  background: var(--cgs-navy-900);
  color: #fff;
  text-decoration: none;
  isolation: isolate;
  transition: transform 260ms var(--ease-out), box-shadow 260ms var(--ease-out);
}
.cgs-service-card:active { transform: scale(0.99); }

.cgs-service-bento__feature { grid-column: 1 / 3; grid-row: 1 / 4; }

.cgs-service-card__media { position: absolute; inset: 0; z-index: -2; }
.cgs-service-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  /* Without this, the global a:hover rule (color: navy-700) outranks
     .cgs-service-card's own color: #fff and the title silently goes
     near-invisible on hover. */
  .cgs-service-card:hover { transform: translateY(-4px); box-shadow: var(--cgs-shadow-lg); color: #fff; }
  .cgs-service-card:hover .cgs-service-card__media img { transform: scale(1.06); }
}

/* The four info cells: description, a secondary photo, CTA, position. */
.cgs-service-bento__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  border-radius: var(--cgs-radius);
  padding: 22px;
}

/* Wide and short: full width of the right-hand column, one row tall. */
.cgs-service-bento__desc {
  grid-column: 3 / 5;
  grid-row: 1 / 2;
  background: var(--cgs-surface);
  justify-content: center;
  gap: 6px;
}
.cgs-service-bento__desc-title {
  font-size: clamp(18px, 1.6vw, 22px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--cgs-ink);
  margin: 0;
}
.cgs-service-bento__desc p {
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--cgs-ink);
  max-width: 46ch;
  margin: 0;
}

/* Narrow and tall: one column, two rows, under the description. A general
   operations photo (real company photography, cycled per service so no
   two services show the same one) rather than an icon or a repeat of the
   feature cell's photo. */
.cgs-service-bento__icon {
  grid-column: 3 / 4;
  grid-row: 2 / 4;
  padding: 0;
  overflow: hidden;
}
.cgs-service-bento__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Small and stacked: single column, single row each, right of the icon.
   The service's own feature photo sits behind the label — a navy scrim
   plus cyan wash keeps "Read more" readable and ties the tile back to the
   feature cell's colour instead of the flat cyan fill it used to be. */
.cgs-service-bento__cta {
  grid-column: 4 / 5;
  grid-row: 2 / 3;
  background: var(--cgs-navy-900);
  color: #fff;
  text-decoration: none;
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  font-weight: 700;
  font-size: 15px;
  overflow: hidden;
  isolation: isolate;
}
.cgs-service-bento__cta-media { position: absolute; inset: 0; z-index: -2; }
.cgs-service-bento__cta-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 600ms var(--ease-out);
}
.cgs-service-bento__cta::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Black scrim — darkens toward the bottom edge so the "Read more" label
     stays legible regardless of what the photo behind it looks like. */
  background: linear-gradient(180deg, rgba(0, 0, 0, .45), rgba(0, 0, 0, .82));
}
.cgs-service-bento__cta-label { display: flex; align-items: center; gap: 6px; transition: color 200ms var(--ease-out); }
.cgs-service-bento__cta i { transition: transform 220ms var(--ease-out), color 200ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .cgs-service-bento__cta:hover .cgs-service-bento__cta-media img { transform: scale(1.08); }
  .cgs-service-bento__cta:hover i { transform: translateX(4px); }
  /* Sea-blue (--cgs-blue-500) on hover — the label and icon (which inherits
     it) swap out of white, the scrim stays black. */
  .cgs-service-bento__cta:hover .cgs-service-bento__cta-label { color: var(--cgs-blue-500); }
}

.cgs-service-bento__index {
  grid-column: 4 / 5;
  grid-row: 3 / 4;
  background: var(--cgs-navy-700);
  color: #fff;
  flex-direction: row;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 3px;
}
.cgs-service-bento__index strong {
  font-size: clamp(32px, 3vw, 44px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
}
.cgs-service-bento__index span { font-size: 14px; font-weight: 600; opacity: .6; padding-bottom: 3px; }

/* The asymmetric desktop placement is line-number-based (grid-column:
   3 / 5 etc.) against a 4-col x 3-row track sized to fill the pinned
   sticky viewport — neither the grid nor the pin exists below 992px
   (cgs.js only pins at min-width:992px), so squeezing the same five
   tiles into one column just produced mismatched cell heights and, on
   the description cell specifically, a large dead gap (its row height
   was driven by the tall secondary photo next to it, not its own
   short text). Below 992px every service collapses to one plain card
   instead: image, title, description, a plain "Read more" link. The
   secondary "general operations" photo (decorative, not tied to the
   specific service — see the PHP template comment) is dropped rather
   than resized, and the numbered index becomes a small pill over the
   image instead of its own full-width tile. */
@media (max-width: 991.98px) {
  .cgs-service-bento {
    display: block;
    position: relative;
    height: auto;
    background: #fff;
    border: 1px solid var(--cgs-line);
    border-radius: var(--cgs-radius);
    overflow: hidden;
    box-shadow: var(--cgs-shadow-lg);
  }
  /* Matches the scoped :not(.swiper-initialized) rule above so this wins
     on source order (same specificity, later in the file) whenever the
     carousel hasn't taken over — e.g. Swiper failing to load. Once
     .swiper-initialized is present neither rule matches and Swiper's own
     slide layout applies instead; the plain .cgs-service-bento
     display:block above already covers the no-JS fallback, where every
     slide stacks unhidden. */
  html.js [data-services-stage]:not(.swiper-initialized) [data-service-slide].is-active { display: block; }

  .cgs-service-bento__feature { aspect-ratio: 16 / 9; border-radius: 0; }

  .cgs-service-bento__icon { display: none; }

  .cgs-service-bento__desc {
    padding: 20px 20px 6px;
    background: transparent;
    justify-content: flex-start;
  }
  .cgs-service-bento__desc p { max-width: none; }

  .cgs-service-bento__cta {
    position: static;
    display: inline-flex;
    margin: 4px 20px 20px;
    padding: 0;
    background: transparent;
    color: var(--cgs-blue-500);
    font-size: 15px;
  }
  .cgs-service-bento__cta-media,
  .cgs-service-bento__cta::before { display: none; }

  .cgs-service-bento__index {
    position: absolute;
    top: 14px;
    left: 14px;
    flex-direction: row;
    align-items: baseline;
    gap: 3px;
    padding: 6px 10px;
    background: rgba(8, 34, 56, .72);
    backdrop-filter: blur(6px);
    border-radius: 999px;
  }
  .cgs-service-bento__index strong { font-size: 13px; }
  .cgs-service-bento__index span { font-size: 12px; padding-bottom: 0; }
}

@media (max-width: 767.98px) {
  .cgs-section-head__right { width: 100%; justify-content: space-between; }
}

/* --- Partners marquee ------------------------------------------------------
   Continuous auto-scroll, not a carousel someone steps through — cgs.js
   drives it with Swiper's own autoplay at a near-zero delay so the strip
   reads as one steady drift rather than discrete slide changes. Edges fade
   via mask-image so logos don't pop in/out at hard edges. Logos pulled from
   the client's old staging site (docs/PROJECT-BRIEF.md open question 13),
   shown in each brand's own colour, not desaturated. */
.cgs-partners { background: var(--cgs-surface); overflow: hidden; }
.cgs-partners__swiper {
  margin-top: clamp(8px, 2vw, 20px);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  /* Swiper's own wrapper transition defaults to ease, which decelerates
     into and re-accelerates out of every step — a "breathing" rhythm, not
     the flat, constant-speed drift a marquee needs. This variable is
     Swiper's own hook for overriding it. */
  --swiper-wrapper-transition-timing-function: linear;
}
.cgs-partners__slide { width: auto; }
.cgs-partners__tile {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 64px;
  padding: 0 clamp(20px, 2.6vw, 32px);
}
.cgs-partners__tile img {
  height: 34px;
  width: auto;
  max-width: 160px;
  object-fit: contain;
}
/* Wordmark fallback for named clients with no verified logo file on disk
   yet (see the $partners comment in index.php) — a plain type lockup
   rather than a guessed-at mark for a real company. */
.cgs-partners__tile--text {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--cgs-slate);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .cgs-partners__swiper { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .cgs-partners__swiper .swiper-wrapper { transform: none !important; }
}

/* --- Divisions ------------------------------------------------------------
   The two named in-house departments from the client's HOME Page email.
   Each division is a numbered card with an intro and a checklist —
   distinct from the services bento above it (photo-led, crossfading) and
   the values grid below it (flat 5-across), so three different section
   families sit back to back rather than three variants of the same card.
   White section background (client: "change unrivaled into white
   background") — was --cgs-teal-500 briefly, before that the shared
   .cgs-section--dark navy. Every text color below is now the plain
   on-light set (navy-900 headings, slate body) instead of the on-dark
   white/cyan set the two earlier backgrounds needed. */
.cgs-divisions { background: #fff; }
.cgs-divisions__head {
  max-width: 760px;
  margin: 0 0 clamp(36px, 4.5vw, 56px);
}
.cgs-divisions__head h2 {
  margin: 0 0 16px;
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-divisions__lede {
  margin: 0;
  font-size: 16px;
  line-height: 1.75;
  color: var(--cgs-slate);
}

/* Division feature module: title/subtitle/description on one side, 3
   asymmetrical photos on the other, then that division's checklist items
   as a card grid below — everything sits directly on the section's white
   background. Shared by both divisions; --reverse (Division 02, client:
   "likewise change division 2 with exact layout in reverse direction")
   swaps which side the gallery lands on via grid order rather than
   duplicating the markup. */
.cgs-division-feature { margin-bottom: clamp(56px, 6vw, 88px); }
.cgs-division-feature__top {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(32px, 4vw, 64px);
  /* Text is shorter than the image stack beside it; pin it to the top of
     the row instead of centering it against the gallery's height. */
  align-items: start;
  margin-bottom: clamp(40px, 5vw, 64px);
}
.cgs-division-feature--reverse .cgs-division-feature__text { order: 2; }
.cgs-division-feature--reverse .cgs-division-feature__gallery { order: 1; }
.cgs-division-feature__num {
  display: block;
  margin-bottom: 14px;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--cgs-blue-500);
}
.cgs-division-feature__text h3 {
  margin: 0 0 14px;
  font-size: clamp(24px, 2.6vw, 32px);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-division-feature__tagline {
  margin: 0 0 16px;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--cgs-blue-500);
}
.cgs-division-feature__intro {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.75;
  color: var(--cgs-slate);
}

/* Gallery: one wide shot, two narrower ones underneath — an asymmetrical
   bento rather than 3 equal tiles. Contained to a viewport-relative
   height (client: "make the 3 images fit with section viewport height in
   a containered way") rather than stacking to whatever height each
   image's own aspect ratio adds up to — the grid rows split that fixed
   height, and object-fit: cover fills each cell without distorting the
   source photos. */
.cgs-division-feature__gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: 1.3fr 1fr;
  gap: 14px;
  height: min(70vh, 620px);
}
.cgs-division-feature__gimg {
  border-radius: var(--cgs-radius);
  overflow: hidden;
  background: var(--cgs-surface);
}
.cgs-division-feature__gimg--wide { grid-column: 1 / -1; }
.cgs-division-feature__gimg img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* A division with only one non-duplicate real photo available (see the
   $divisionMedia comment in index.php) gets a single full-bleed image
   instead of forcing the 1-wide-plus-2-narrow composition with a repeat.
   Sized to exactly match the top wide tile's own box in the 3-image
   layout above (row 1 of the 1.3fr/1fr split, minus the 14px row gap) —
   client: "I want that top 1st image height and width applied for this
   single image" — rather than an independently-chosen aspect ratio, so a
   division that later gains its other two photos back slots into the
   same footprint the wide tile already occupies. Width needs no override:
   the tile already spans the full grid width, same as the wide tile. */
.cgs-division-feature__gallery--solo {
  height: calc((min(70vh, 620px) - 14px) * 1.3 / 2.3);
  align-self: center;
}
.cgs-division-feature__gallery--solo .cgs-division-feature__gimg {
  grid-column: 1 / -1;
  grid-row: 1 / -1;
}

.cgs-division-feature__points {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.cgs-point-card {
  padding: clamp(20px, 2.2vw, 26px);
  background: #fff;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-point-card i {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-bottom: 14px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-blue-500);
  font-size: 12px;
}
.cgs-point-card h4 {
  margin: 0 0 8px;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--cgs-navy-900);
}
.cgs-point-card p {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--cgs-slate);
}

@media (max-width: 991.98px) {
  .cgs-division-feature__top { grid-template-columns: 1fr; }
  /* Order only matters for the desktop 2-column row; stacked single-column
     it should always read text-then-gallery regardless of --reverse. */
  .cgs-division-feature--reverse .cgs-division-feature__text,
  .cgs-division-feature--reverse .cgs-division-feature__gallery { order: initial; }
  .cgs-division-feature__points { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
  .cgs-division-feature__points { grid-template-columns: 1fr; }
  /* 3 stacked images can't share the same fixed viewport-height box the
     2-row desktop grid uses without squashing — fall back to each
     image's own aspect ratio and let the gallery grow naturally. */
  .cgs-division-feature__gallery { grid-template-columns: 1fr; grid-template-rows: none; height: auto; }
  .cgs-division-feature__gimg--wide { grid-column: auto; }
  .cgs-division-feature__gimg--wide img { aspect-ratio: 16 / 10; }
  .cgs-division-feature__gimg:not(.cgs-division-feature__gimg--wide) img { aspect-ratio: 4 / 3; }
}

/* Closing "why choose CGS" strip: a tighter, icon-led rhythm inside the
   same band, separated by a hairline rather than starting a new section —
   the client wrote both halves as one continuous email. Text below is the
   on-light set to match the section's white background; the icon badge
   keeps its navy-900 fill unchanged, since a solid dark badge reads just
   as well floating on white as it did on the darker backgrounds before. */
.cgs-advantage {
  padding-top: clamp(36px, 4.5vw, 56px);
  border-top: 1px solid var(--cgs-line);
}
.cgs-advantage h3 {
  margin: 0 0 clamp(28px, 3.5vw, 40px);
  font-size: clamp(22px, 2.6vw, 30px);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
/* 3 columns, not 4: the standalone 6-item "CGS Advantage" section
   (index.php) reads as a clean 2x3 grid this way. The card content and
   icon badge styling below is unchanged from when this lived inside
   Divisions with 4 items. */
.cgs-advantage__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 2.4vw, 32px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.cgs-advantage__icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 16px;
  border-radius: 50%;
  /* Solid navy-900 fill, not a translucent white circle: at 8% opacity the
     badge was nearly invisible on --cgs-teal-500. Navy also ties the badge
     back to the division cards' own material a few rows above. */
  background: var(--cgs-navy-900);
  color: var(--cgs-cyan-300);
  font-size: 18px;
}
.cgs-advantage__grid strong {
  display: block;
  margin-bottom: 8px;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--cgs-navy-900);
}
.cgs-advantage__grid p {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--cgs-slate);
}
@media (max-width: 991.98px) {
  .cgs-advantage__grid { grid-template-columns: repeat(2, 1fr); gap: 28px; }
}
@media (max-width: 575.98px) {
  .cgs-advantage__grid { grid-template-columns: 1fr; }
}

/* --- Our Story --------------------------------------------------------------
   2026-08-21: rebuilt to match the layout the client pointed at
   (reference/roofer/about.php's "About" section) — two plain columns, each
   its own photo + paragraph, the left one closing on a 2x2 stat grid and
   the right one opening on an eyebrow + heading. Unlike the Roofer
   reference, every stat below is a real, sourced fact (see the $ourStory
   comment in index.php) — no invented counters. */
.cgs-story__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.cgs-story__col { display: flex; flex-direction: column; }
.cgs-story__media {
  border-radius: var(--cgs-radius);
  overflow: hidden;
  background: var(--cgs-line);
  box-shadow: var(--cgs-shadow);
}
.cgs-story__media img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}
.cgs-story__col > .cgs-story__media { margin-bottom: 28px; }
/* Right column's photo comes last (eyebrow, heading, paragraph, then the
   image) — no trailing margin needed once it's the final element. */
.cgs-story__col > .cgs-story__media:last-child { margin-bottom: 0; }
.cgs-story__col > p {
  margin: 0 0 32px;
  font-size: 16.5px;
  line-height: 1.75;
  color: var(--cgs-slate);
}

.cgs-story__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 16px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-story__eyebrow i { font-size: 12px; color: var(--cgs-cyan-400); }

.cgs-story__col h2 {
  margin: 0 0 16px;
  font-size: clamp(26px, 3vw, 36px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}

/* Plain 2x2 stat grid, no card chrome — a big bold value and a short
   caption underneath, same rhythm as the reference's counter blocks but
   sourced facts (founding year, WCA membership, ISO/bizSAFE certification)
   in place of its placeholder project/staff/satisfaction counters. */
.cgs-story__stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px 24px;
  padding-top: 28px;
  border-top: 1px solid var(--cgs-line);
}
.cgs-story__stat strong {
  display: block;
  margin-bottom: 8px;
  font-size: clamp(24px, 2.4vw, 30px);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--cgs-navy-900);
}
/* ISO/bizSAFE cells: the real registrar badge in place of the bold
   number, sized to sit on the same baseline the other two cells' text
   occupies rather than at its own native size. */
.cgs-story__stat-logo {
  display: block;
  height: 46px;
  width: auto;
  max-width: 100%;
  margin-bottom: 10px;
  object-fit: contain;
  object-position: left center;
}
/* The ISO seal is a tight circle with a lot of its own internal padding,
   so at the same height as the bizSAFE wordmark it reads visibly smaller
   (client: "make it bigger like bizsafe logo") — sized up on its own
   rather than raising the shared height, which would blow up bizSAFE too. */
.cgs-story__stat-logo[src*="badge-iso9001"] {
  height: 62px;
  margin-bottom: 4px;
}
/* "15+ Years as a WCA Project member" cell: the WCA Projects mark sits
   inline next to the number instead of replacing it (client, 2026-08-26:
   "paste this as well" alongside the ISO/bizSAFE logos) — a standalone
   5th grid cell left one item orphaned on its own row in this 2-column
   grid, and the "15+" fact is still worth keeping next to the mark. */
.cgs-story__stat-combo {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}
.cgs-story__stat-combo strong {
  margin-bottom: 0;
}
.cgs-story__stat-mark {
  height: 34px;
  width: auto;
  object-fit: contain;
}
.cgs-story__stat span {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--cgs-muted);
}

@media (max-width: 991.98px) {
  .cgs-story__grid { grid-template-columns: 1fr; gap: 40px; }
  /* Stacked order, mobile/tablet only: the right column (eyebrow, heading,
     narrative, closing photo) reads as the section's opener, so it goes on
     top; the left column (opening photo, paragraph, WCA/ISO/bizSAFE stat
     grid) follows underneath. Desktop keeps its left/right layout as-is —
     this is purely a stacking-order swap, not a rewrite of the grid. */
  .cgs-story__col:first-child { order: 2; }
  .cgs-story__col:last-child { order: 1; }
}
@media (max-width: 575.98px) {
  .cgs-story__stats { grid-template-columns: 1fr; gap: 20px; }
  /* Single-column stack reads better centered than left-hugging one narrow
     line at a time — value/logo and caption both center under each other. */
  .cgs-story__stat { text-align: center; }
  .cgs-story__stat-logo { margin-left: auto; margin-right: auto; object-position: center; }
  .cgs-story__stat-combo { justify-content: center; }
}

/* --- Mission & Vision -------------------------------------------------------
   Replaces the "Waypoint" concept below (now hidden, same convention as
   the rest of this file) — client, with a reference screenshot: "Mission
   right side text left image on top a image total 2 images ... reverse
   the same for [vision]". One feature row per pillar: a two-photo
   collage (a large lead photo with a smaller accent photo overlapping
   its lower-right corner, bordered in the section's own background so it
   reads as sitting on top rather than pasted over the edge) beside the
   heading and body copy, sides alternating via --reverse. Same dark navy
   band as Waypoint used (.cgs-section--dark — client: "with same
   background"), so this is a layout change inside an unchanged section,
   not a new one-off. */
.cgs-mv__list {
  display: flex;
  flex-direction: column;
  gap: clamp(64px, 8vw, 100px);
}

/* Column split, ordering and the mobile stack are all plain Bootstrap
   (.row / .col-lg-6 / .order-lg-*) on the markup side now — this file only
   styles what those columns contain. The row is align-items-stretch
   (client: "make the image exactly align with text height"), and unlike
   CSS Grid's auto tracks, a stretched flex item gets a real, definite
   height its children can resolve percentages against — so height: 100%
   below actually reaches the text column's height instead of falling
   back to the photo's own intrinsic ratio. */
.cgs-mv-feature__gallery { position: relative; height: 100%; }

.cgs-mv-feature__img--main {
  height: 100%;
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-mv-feature__img--main img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The accent photo overlaps the main one rather than sitting beside it —
   the border matches the section's own navy so it reads as a second
   print laid on top, not a thumbnail pasted over the edge. */
.cgs-mv-feature__img--accent {
  position: absolute;
  right: 6%;
  bottom: -8%;
  width: 46%;
  aspect-ratio: 1 / 1;
  border-radius: var(--cgs-radius);
  overflow: hidden;
  border: 6px solid var(--cgs-navy-900);
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-mv-feature__img--accent img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The column is as tall as the stretched photo beside it now, so its
   content is centered in that height rather than pinned to the top. */
.cgs-mv-feature__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.cgs-mv-feature__icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 20px;
  border-radius: 50%;
  background: rgba(46, 159, 214, 0.14);
  border: 1px solid rgba(46, 159, 214, 0.32);
  color: var(--cgs-cyan-300);
  font-size: 18px;
}
.cgs-mv-feature__text h3 {
  margin: 0 0 16px;
  font-size: clamp(24px, 2.8vw, 32px);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.cgs-mv-feature__text p {
  margin: 0;
  font-size: 17px;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.72);
  max-width: 46ch;
}

/* Below lg, .col-lg-6 stacks the gallery and text into separate flex
   lines, so stretch no longer ties the photo's height to the text — back
   to the photo asserting its own ratio here. */
@media (max-width: 991.98px) {
  .cgs-mv-feature__gallery { height: auto; }
  .cgs-mv-feature__img--main { height: auto; aspect-ratio: 4 / 5; }
}

@media (max-width: 767.98px) {
  .cgs-mv-feature__img--accent { width: 50%; right: 4%; bottom: -6%; }
}

/* --- Mission & Vision: "Waypoint" (superseded, hidden) --------------------
   Retained only because the markup that used it is hidden via if (false)
   in index.php, not deleted — same convention as every other superseded
   section on this page. Superseded 2026-08-21 by .cgs-mv above. Mission
   and Vision read as two waypoints on one plotted course: a dashed
   bearing line between the cards with a vessel icon drifting along it,
   and each card's photo set inside a circular "porthole" bezel instead
   of a rectangular thumbnail. */
.cgs-waypoint {
  position: relative;
  overflow: hidden;
}
.cgs-waypoint > .container-fluid { position: relative; }

.cgs-waypoint__head {
  text-align: center;
  max-width: 640px;
  margin: 0 auto clamp(40px, 5vw, 60px);
}
.cgs-waypoint__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 18px;
  padding: 7px 16px;
  font-family: var(--cgs-font);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cgs-cyan-300);
  background: rgba(8, 34, 56, 0.55);
  border: 1px solid rgba(46, 159, 214, 0.34);
  border-radius: 100px;
}
.cgs-waypoint__eyebrow i { color: var(--cgs-cyan-400); }
.cgs-waypoint__head h2 {
  margin: 0;
  font-size: clamp(24px, 3vw, 34px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.cgs-waypoint__route {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(24px, 3vw, 40px);
}

.cgs-waypoint-card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  padding: clamp(26px, 3vw, 34px) clamp(24px, 3vw, 32px);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
  border: 1px solid rgba(46, 159, 214, 0.22);
  border-radius: var(--cgs-radius);
}

.cgs-waypoint-card__marker {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 22px;
  font-family: var(--cgs-font);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.cgs-waypoint-card__marker b { color: var(--cgs-cyan-300); font-weight: 600; }
.cgs-waypoint-card__dot {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(46, 159, 214, 0.34);
}
.cgs-waypoint-card__dot span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--cgs-cyan-400);
}

/* Porthole: a ship's-window bezel around the real operations photo,
   rather than a rectangular card thumbnail — the icon that used to sit in
   a plain badge moves to a small corner rivet on the rim instead. */
.cgs-waypoint-card__medallion {
  position: relative;
  width: 76px;
  margin: 0 0 20px;
}
.cgs-waypoint-card__porthole {
  display: block;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  box-shadow:
    0 0 0 4px var(--cgs-navy-900),
    0 0 0 5px rgba(46, 159, 214, 0.4),
    inset 0 0 0 2px rgba(255, 255, 255, 0.07);
}
.cgs-waypoint-card__porthole img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.92) brightness(0.9);
}
.cgs-waypoint-card__porthole::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, rgba(8, 34, 56, 0.08), rgba(8, 34, 56, 0.6));
  mix-blend-mode: multiply;
}
.cgs-waypoint-card__glare {
  position: absolute;
  top: 7%;
  left: 15%;
  width: 42%;
  height: 20%;
  border-radius: 50%;
  background: linear-gradient(120deg, rgba(255, 255, 255, 0.38), transparent 75%);
  filter: blur(1px);
}
.cgs-waypoint-card__badge {
  position: absolute;
  right: -4px;
  bottom: -4px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(46, 159, 214, 0.4);
  color: var(--cgs-cyan-300);
  font-size: 12px;
}

.cgs-waypoint-card h3 {
  margin: 0 0 12px;
  font-size: clamp(20px, 2.2vw, 24px);
  font-weight: 800;
  letter-spacing: -0.01em;
}
.cgs-waypoint-card p {
  margin: 0;
  font-size: 16px;
  line-height: 1.72;
  color: rgba(255, 255, 255, 0.72);
  flex: 1 0 auto;
}

@media (max-width: 767.98px) {
  .cgs-waypoint__route { grid-template-columns: 1fr; }
}

/* --- Mission & Vision (old paired-card layout, hidden) --------------------
   Retained only because the markup that used it is hidden via if (false)
   in index.php, not deleted — same convention as every other superseded
   section on this page. Superseded 2026-08-21 by .cgs-waypoint above. */
.cgs-pillars__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(24px, 3vw, 40px);
}
.cgs-pillar-card {
  overflow: hidden;
  border-radius: var(--cgs-radius);
  background: #fff;
  border: 1px solid var(--cgs-line);
  box-shadow: var(--cgs-shadow);
}
.cgs-pillar-card__media { background: var(--cgs-line); }
.cgs-pillar-card__media img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.cgs-pillar-card__body { padding: clamp(24px, 3vw, 32px); }
/* Plain in-flow badge, same treatment as .cgs-advantage__icon — not
   overlaid on the photo above it. */
.cgs-pillar-card__icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 16px;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  color: var(--cgs-cyan-300);
  font-size: 17px;
}
.cgs-pillar-card h3 {
  margin: 0 0 12px;
  font-size: clamp(20px, 2.2vw, 24px);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--cgs-navy-900);
}
.cgs-pillar-card p {
  margin: 0;
  font-size: 16px;
  line-height: 1.7;
  color: var(--cgs-slate);
}

@media (max-width: 767.98px) {
  .cgs-pillars__grid { grid-template-columns: 1fr; }
}

/* --- Testimonials -------------------------------------------------------
   New for the 2026-08-21 redesign, the 3 real client quotes from
   docs/source/Home page CGS.docx. Rebuilt 2026-08-21 as a single-quote
   Swiper carousel (client: "make the testimonials swiper with pagination
   and controls and it moves autoplay") — replaces the old divided 3-up
   grid, since a carousel that already shows every slide at once has
   nothing left to move. Arrow buttons reuse the same visual treatment as
   .cgs-services__arrow (kept as its own class rather than shared, same
   per-section-prefix convention as the rest of this file). */
.cgs-testimonials__arrows { display: flex; align-items: center; gap: 10px; }
.cgs-testimonials__arrow {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  padding: 0;
  border: 1.5px solid var(--cgs-line);
  border-radius: 50%;
  background: transparent;
  color: var(--cgs-navy-900);
  font-size: 14px;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              color 200ms var(--ease-out),
              transform 160ms var(--ease-out);
}
.cgs-testimonials__arrow:active { transform: scale(0.94); }
.cgs-testimonials__arrow:disabled { opacity: .38; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .cgs-testimonials__arrow:not(:disabled):hover {
    background: var(--cgs-navy-900);
    border-color: var(--cgs-navy-900);
    color: #fff;
  }
}

.cgs-testimonials__swiper {
  padding-bottom: clamp(44px, 5vw, 56px);
  overflow: hidden;
}
.cgs-testimonials__grid { margin: 0; padding: 0; list-style: none; }

/* Fixed height, not auto or 100% — Swiper positions slides with transforms
   rather than flex layout, so it never actually stretched these to match
   each other despite slidesPerView:3 putting three different-length quotes
   side by side. A flat height (comfortably above the longest quote at any
   breakpoint) keeps every card the same size instead; blockquote's flex:1
   below still pins the footer to the bottom on the shorter ones. */
.cgs-testimonial {
  display: flex;
  flex-direction: column;
  height: 490px;
  padding: clamp(32px, 4vw, 44px);
  background: #fff;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  box-shadow: var(--cgs-shadow);
}
.cgs-testimonial__icon {
  margin-bottom: 18px;
  font-size: 22px;
  color: var(--cgs-cyan-400);
}
.cgs-testimonial blockquote {
  flex: 1 1 auto;
  margin: 0 0 24px;
  font-size: clamp(16px, 1.8vw, 18px);
  line-height: 1.75;
  color: var(--cgs-ink);
}
.cgs-testimonial footer {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 18px;
  border-top: 1px solid var(--cgs-line);
}
.cgs-testimonial__name { font-size: 14.5px; font-weight: 700; color: var(--cgs-navy-900); }
.cgs-testimonial__company { font-size: 13px; color: var(--cgs-muted); }

/* Pagination — same clickable-dot language as the hero carousel, tuned
   for a light section instead of the hero's dark scrim. */
.cgs-testimonials__pagination {
  bottom: 0 !important;
}
.cgs-testimonials__pagination .swiper-pagination-bullet {
  width: 8px;
  height: 8px;
  background: var(--cgs-line);
  opacity: 1;
  transition: background-color 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.cgs-testimonials__pagination .swiper-pagination-bullet-active {
  background: var(--cgs-blue-500);
  transform: scale(1.25);
}

/* --- Accent CTA card ------------------------------------------------------
   Single-use, single-accent card ("Send us your packing list"), ported from
   the "Hyer" landing concept's featured clay card. Full-bleed on the same
   --cgs-teal-500 used for the top bar, so the two read as one accent
   rather than two different blues.
   Divisions (directly above) is white now, so the white-to-teal boundary
   is already a strong seam on its own — no extra hairline needed here
   (a translucent white one would have half-vanished against the white
   section feeding into it anyway). */
.cgs-accent-cta { background: var(--cgs-teal-500); }
.cgs-accent-cta__inner {
  padding-block: clamp(48px, 6vw, 72px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
  max-width: 640px;
}
.cgs-accent-cta__inner h2 {
  margin: 0;
  font-size: clamp(28px, 4vw, 44px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: #fff;
  text-wrap: balance;
}
.cgs-accent-cta__inner p {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: #fff;
}
.cgs-accent-cta .cgs-btn--on-dark {
  background: var(--cgs-navy-900);
  color: #fff;
}
.cgs-accent-cta .cgs-btn--on-dark:hover { background: var(--cgs-navy-700); color: #fff; }

/* Reusable tint background — a section that wants to stand apart from the
   plain-white sections around it without going full dark. */
.cgs-section--tint { background: var(--cgs-surface); }

/* --- Fleet split --------------------------------------------------------- */

.cgs-split {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}

/* Offset pair: the second image drops and overlaps, so the block reads as a
   composition rather than a single stock photo in a box. */
.cgs-split__media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
}
.cgs-split__media img {
  width: 100%;
  height: 100%;
  border-radius: var(--cgs-radius);
  object-fit: cover;
}
.cgs-split__media img:first-child { aspect-ratio: 4 / 5; }
.cgs-split__media img:last-child  { aspect-ratio: 3 / 4; margin-top: clamp(24px, 5vw, 56px); }

/* Entrance dramatises the composition above rather than a generic fade:
   the back image settles quietly in place; the front, overlapping image
   visibly drops into its offset a beat later — cgs.js toggles one class
   on first view, off entirely under reduced motion. */
html.js .cgs-split__media img {
  opacity: 0;
  transition: opacity 620ms var(--ease-out), transform 620ms var(--ease-out);
}
html.js .cgs-split__media img:first-child { transform: scale(0.96); }
html.js .cgs-split__media img:last-child {
  transform: translateY(28px) scale(0.97);
  transition-delay: 160ms;
}
html.js .cgs-split__media.is-visible img { opacity: 1; transform: none; }

.cgs-split__body h2 {
  margin: 0 0 16px;
  font-size: clamp(26px, 3.4vw, 40px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  text-wrap: balance;
}
.cgs-split__body > p {
  margin: 0 0 26px;
  max-width: 52ch;
  font-size: 17px;
  line-height: 1.75;
  color: var(--cgs-ink);
}

.cgs-split__points { margin: 0 0 28px; padding: 0; list-style: none; }
.cgs-split__points li {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 15px 0 15px 20px;
  border-left: 2px solid var(--cgs-line);
  transition: border-color 220ms var(--ease-out);
}
.cgs-split__points li:hover { border-left-color: var(--cgs-cyan-400); }
.cgs-split__points strong { font-size: 15.5px; font-weight: 700; color: var(--cgs-ink); }
.cgs-split__points span { font-size: 14.5px; line-height: 1.65; color: var(--cgs-ink); }

@media (max-width: 991.98px) {
  .cgs-split { grid-template-columns: 1fr; }
}

/* --- Closing CTA ---------------------------------------------------------
   Dark navy card, copy on the left and the actions on the right — a
   deliberate switch from the previous centred cyan card. Two quiet SVG
   flourishes (a hairline squiggle top-left, dashed orbit rings behind the
   actions) stand in for the amber accents of the reference this was
   modelled on: this brand runs no warm colour at all, so the rings use
   --cgs-cyan-400 instead and the button stays the existing white
   --cgs-btn--on-dark fill, which is already built to read on any dark
   ground. */

/* The negative margin lives on the CARD, not the section: a negative
   bottom margin on the last in-flow child shrinks its parent's auto
   height by that same amount, so the white .cgs-cta box ends early —
   short of the card's own full height — while the card itself keeps
   painting past that point, overflowing (visibly, nothing here clips
   it) into the footer below. z-index on the section lifts that
   overflowing strip of the card above the footer's own background, so
   it reads as the card resting on the footer rather than the footer
   covering it. .cgs-footer adds the same amount back as padding-top so
   its own columns still clear the card.
   flow-root on the inner wrapper matters: with no padding/border of its
   own on that edge, the card's negative margin would otherwise collapse
   straight through it (and through .cgs-cta too) and come out the other
   side as .cgs-cta's own margin — shrinking nothing and just pulling the
   footer under the still-full-height white section instead of letting
   the card poke through it. */
.cgs-cta {
  position: relative;
  z-index: 2;
  padding-block: clamp(40px, 5vw, 64px) 0;
  background: #fff;
}
.cgs-cta > .container-fluid { display: flow-root; }
/* Only pages that actually end on this CTA get the extra top clearance on
   the footer — otherwise every other page's footer would carry the same
   gap with no floating card to justify it. */
main:has(> .cgs-cta:last-child) + .cgs-footer { padding-top: var(--cgs-cta-overlap); }
.cgs-cta__card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: clamp(24px, 4vw, 48px);
  padding: clamp(40px, 6vw, 56px) clamp(28px, 5vw, 64px);
  margin-bottom: calc(-1 * var(--cgs-cta-overlap));
  border-radius: clamp(20px, 2.4vw, 28px);
  background: radial-gradient(130% 160% at 100% 100%, var(--cgs-navy-900) 0%, var(--cgs-teal-500) 55%);
  color: #fff;
  box-shadow: var(--cgs-shadow-float);
}
.cgs-cta__card::before,
.cgs-cta__card::after {
  content: '';
  position: absolute;
  z-index: 0;
  pointer-events: none;
}
/* Hairline squiggle, top-left corner. */
.cgs-cta__card::before {
  top: -8px;
  left: -8px;
  width: clamp(120px, 14vw, 170px);
  height: clamp(72px, 8vw, 100px);
  opacity: .3;
  background-repeat: no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='100' viewBox='0 0 170 100'%3E%3Cpath d='M4 62 C22 16 46 16 58 44 C68 68 90 68 100 42 C107 24 107 10 96 6' stroke='white' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
}
/* Dashed orbit rings, sitting behind the actions column. Colour comes from
   background-color, not the SVG: the data URI only supplies shape through
   a mask, so this stays on --cgs-cyan-400 if that token ever moves,
   instead of quietly drifting like the old --cgs-accent amber did. */
.cgs-cta__card::after {
  right: clamp(-30px, 3vw, 0px);
  bottom: clamp(-60px, -6vw, -30px);
  width: clamp(180px, 20vw, 260px);
  height: clamp(180px, 20vw, 260px);
  opacity: .55;
  background-color: var(--cgs-cyan-400);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260' viewBox='0 0 260 260'%3E%3Ccircle cx='130' cy='130' r='118' fill='none' stroke='%23000' stroke-width='1.5' stroke-dasharray='2 7'/%3E%3Ccircle cx='130' cy='130' r='84' fill='none' stroke='%23000' stroke-width='1.5' stroke-dasharray='2 6'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260' viewBox='0 0 260 260'%3E%3Ccircle cx='130' cy='130' r='118' fill='none' stroke='%23000' stroke-width='1.5' stroke-dasharray='2 7'/%3E%3Ccircle cx='130' cy='130' r='84' fill='none' stroke='%23000' stroke-width='1.5' stroke-dasharray='2 6'/%3E%3C/svg%3E");
}
.cgs-cta__copy {
  position: relative;
  z-index: 1;
  flex: 1 1 380px;
  max-width: 56ch;
}
.cgs-cta__card h2 {
  margin: 0 0 14px;
  font-size: clamp(26px, 3.6vw, 42px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: #fff;
  text-wrap: balance;
}
/* Full opacity, not the usual muted white: this card's copy sits over the
   lighter --cgs-teal-500 end of the gradient (reversed to lead with teal),
   where dimmed white reads as low-contrast and hard to read. A faint
   text-shadow keeps it legible even in the small strip where the gradient
   passes back through a mid-tone. */
.cgs-cta__card p {
  margin: 0;
  max-width: 50ch;
  font-size: 17.5px;
  line-height: 1.7;
  color: #fff;
  text-shadow: 0 1px 10px rgba(8, 34, 56, .35);
}
.cgs-cta__actions {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  flex-shrink: 0;
}

@media (max-width: 575.98px) {
  /* .cgs-cta__actions is flex-shrink:0 with an auto flex-basis (it needs
     to hug its content at desktop widths, sitting next to the copy rather
     than stretching). A child at width:100% resolves against that auto
     basis using its own max-content size, not the card's actual width —
     so without pinning the container itself to 100% here too, the button
     column ends up wider than the card and .cgs-cta__card's overflow:
     hidden silently clips the right edge of every button. */
  .cgs-cta__actions { flex-basis: 100%; width: 100%; }
  .cgs-cta__actions .cgs-btn { width: 100%; justify-content: center; }
}

/* --- Project desk ----------------------------------------------------------
   Role-based contact grid ("Contact Our Project Desk"), real named people
   and department addresses from the client's HOME Page email. Plain cards,
   left-aligned, no photos — this is a directory, not a team-bio section. */
.cgs-desk {
  /* Partners (above) and this section both use .cgs-section--tint's
     --cgs-surface fill; with the accent CTA that used to sit between them
     removed, they were fusing into one flat block. Same fix as the
     Divisions/CTA seam: a hairline in the on-light color. */
  border-top: 1px solid var(--cgs-line);
  position: relative;
  overflow: hidden;
}
/* Corner watermark, tried here after being rejected for the homepage in
   general (client: "push this and try it in contact section" — this desk
   grid is the closest thing this page has to a contact section). The
   source file (assets/img/bg/Oil-rig-icon-background-2.png) is a
   multi-tone grey clipart illustration that clashed with the rest of the
   page's abstract line-art decoration (the CTA card's dashed orbit rings,
   the hairline squiggle) and its all-real-photography content — so
   instead of placing the raw asset, its alpha shape drives a CSS mask
   filled with a single flat brand tone at low opacity, the same technique
   the CTA card's ::after ring already uses, just fed by a raster mask
   instead of an inline SVG one. assets/img/bg/oil-rig-illustration.png is
   a cropped-to-content, downscaled, palette-quantized copy of that source
   file (1000x893, 38KB) — the original 8000x4500 PNG is left untouched
   on disk. */
.cgs-desk::after {
  content: '';
  position: absolute;
  z-index: 0;
  right: clamp(-10px, 1.5vw, 12px);
  bottom: 0;
  width: clamp(200px, 24vw, 380px);
  aspect-ratio: 1000 / 893;
  background-color: var(--cgs-blue-500);
  opacity: .08;
  -webkit-mask-image: url("../img/bg/oil-rig-illustration.png");
          mask-image: url("../img/bg/oil-rig-illustration.png");
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: bottom right;
          mask-position: bottom right;
  -webkit-mask-size: contain;
          mask-size: contain;
  pointer-events: none;
}
.cgs-desk__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1px;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--cgs-line);
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-desk__grid li {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 24px 20px;
  background: #fff;
}
.cgs-desk__role {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-desk__name { font-size: 15.5px; font-weight: 700; color: var(--cgs-ink); }
.cgs-desk__email {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  font-size: 13px;
  color: var(--cgs-slate);
  text-decoration: none;
  word-break: break-word;
}
.cgs-desk__email i { font-size: 11px; color: var(--cgs-cyan-400); }
.cgs-desk__email:hover { color: var(--cgs-blue-500); }

@media (max-width: 991.98px) {
  .cgs-desk__grid { grid-template-columns: repeat(2, 1fr); }
  /* 5 items in a 2-column grid leaves the 6th cell showing the grid's own
     gap background as a blank box. Only meaningful at this 2-column
     width. */
  .cgs-desk__grid li:nth-child(5) { grid-column: 1 / -1; }
}
@media (max-width: 575.98px) {
  .cgs-desk__grid { grid-template-columns: 1fr; }
  .cgs-desk__grid li:nth-child(5) { grid-column: auto; }
}

/* --- Gallery ---------------------------------------------------------------
   Real operations photography ($galleryShots, index.php), laid out as a
   masonry column flow rather than a fixed-height grid so every photo —
   portrait or landscape — keeps its own natural aspect ratio (client:
   "place portrait images in correct layout"). break-inside: avoid keeps
   each photo whole instead of splitting it across two columns. Click opens
   the full photo in a Magnific Popup lightbox with gallery navigation
   (init in includes/scripts.php). */
.cgs-gallery { background: #fff; }
.cgs-gallery__grid {
  column-count: 3;
  column-gap: 14px;
}
.cgs-gallery__tile {
  position: relative;
  display: block;
  break-inside: avoid;
  margin-bottom: 14px;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  background: var(--cgs-surface);
  text-decoration: none;
}
.cgs-gallery__tile img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 400ms var(--ease-in-out);
}
.cgs-gallery__tile:hover img,
.cgs-gallery__tile:focus-visible img { transform: scale(1.05); }

.cgs-gallery__caption {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px;
  padding: 16px;
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.4;
  background: linear-gradient(180deg, transparent, rgba(8, 34, 56, .82) 85%);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.cgs-gallery__tile:hover .cgs-gallery__caption,
.cgs-gallery__tile:focus-visible .cgs-gallery__caption { opacity: 1; transform: translateY(0); }
/* Past Projects: client wants the hover caption gone entirely — with no
   filter bar or other per-photo labelling on this page any more, a caption
   would just repeat the alt text for no reason. Scoped to this page only;
   the homepage's hidden gallery section (see comment above) keeps captions. */
.page-past-projects .cgs-gallery__caption { display: none; }
.cgs-gallery__caption i {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .18);
  font-size: 11px;
}

@media (max-width: 991.98px) {
  .cgs-gallery__grid { column-count: 2; }
  /* Hover-only caption is unreachable on touch; show it plainly instead. */
  .cgs-gallery__caption {
    position: static;
    opacity: 1;
    transform: none;
    padding: 10px 2px 0;
    color: var(--cgs-slate);
    background: none;
  }
  .cgs-gallery__caption i { display: none; }
}
@media (max-width: 575.98px) {
  .cgs-gallery__grid { column-count: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .cgs-gallery__tile:hover img,
  .cgs-gallery__tile:focus-visible img { transform: none; }
}

/* Past Projects: every row — including the last — bottoms out in a
   straight line, permanently, no matter how many photos get added later
   (2026-08-29, client: aligned "even if new images added in future").
   Masonry can't promise that structurally: whichever column ends up
   tallest after the *next* upload determines where the ragged edge falls,
   so column-count is swapped for a real grid of fixed-ratio cells here —
   object-fit: cover crops each photo to fill its cell instead of the
   masonry's natural-aspect-ratio tiles above. Scoped to this page only;
   the homepage's hidden gallery section keeps the masonry look. */
.page-past-projects .cgs-gallery__grid {
  column-count: unset;
  column-gap: unset;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
.page-past-projects .cgs-gallery__tile {
  break-inside: unset;
  margin-bottom: 0;
  aspect-ratio: 4 / 5;
}
.page-past-projects .cgs-gallery__tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (max-width: 991.98px) {
  .page-past-projects .cgs-gallery__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
  .page-past-projects .cgs-gallery__grid { grid-template-columns: 1fr; }
}

/* --- Past Projects: intro strip ---------------------------------------------
   past-projects.php only. Used to sit above a category filter bar
   (?category=<slug> chips) — removed 2026-08-29, client call, so this is
   just the intro copy + photo count directly above the plain gallery grid
   now. */
.cgs-projects__intro { max-width: 62ch; margin: 0 0 clamp(28px, 3.5vw, 40px); }
.cgs-projects__intro h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-projects__intro p { margin: 0; font-size: 16.5px; line-height: 1.7; color: var(--cgs-slate); }
.cgs-projects__intro p.cgs-projects__count {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--cgs-blue-500);
}
.cgs-projects__count i { font-size: 11px; color: var(--cgs-cyan-400); }

/* --- Past Projects: gallery pagination --------------------------------------
   The masonry grid above (.cgs-gallery__grid, column-count) intentionally
   lets each photo keep its natural aspect ratio, so its columns never
   bottom out at the same height — the last row is inherently ragged. The
   top border + generous margin-top here (2026-08-29, client: pagination
   "must be aligned" at the end) is what makes the transition read as
   deliberate rather than like the grid just trailed off unevenly: a clear
   horizontal rule the pagination row sits on, regardless of which column
   is tallest above it. */
.cgs-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 48px 0 4px;
  padding-top: 28px;
  border-top: 1px solid var(--cgs-line);
}
.cgs-pagination__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 38px;
  height: 38px;
  padding: 0 12px;
  justify-content: center;
  border-radius: var(--cgs-radius);
  border: 1.5px solid var(--cgs-line);
  background: #fff;
  color: var(--cgs-navy-900);
  font-family: var(--cgs-font);
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  transition: background-color 180ms var(--ease-out), border-color 180ms var(--ease-out), color 180ms var(--ease-out);
}
.cgs-pagination__link:hover { border-color: var(--cgs-blue-500); color: var(--cgs-blue-500); }
.cgs-pagination__link.is-active {
  background: var(--cgs-navy-900);
  border-color: var(--cgs-navy-900);
  color: #fff;
  cursor: default;
}
.cgs-pagination__link.is-disabled {
  opacity: 0.4;
  pointer-events: none;
}
.cgs-pagination__ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 38px;
  color: var(--cgs-muted);
  font-weight: 700;
}
@media (max-width: 575.98px) {
  .cgs-pagination__link--prev span,
  .cgs-pagination__link--next span { display: none; }
  .cgs-pagination__link--prev,
  .cgs-pagination__link--next { padding: 0 10px; }
}

/* --- Past Projects: video section ------------------------------------------
   A real grid, sized for however many videos exist (currently one card per
   gallery category — see the $pastVideos comment in past-projects.php),
   not a single teaser box. Cards are legitimately uniform: this is a video
   library, where identical-shaped tiles are the expected pattern, not the
   forced three-card symmetry the Shape Consistency note above warns against
   for thin feature copy. Card radius matches .cgs-cta__card's larger
   "feature card" scale, not the 4px .cgs-gallery__tile / .cgs-pagination__link scale —
   this site's second, already-established radius tier for hero-weight
   panels. .cgs-video-trigger (real youtube_id set) opens Magnific Popup's
   iframe/YouTube lightbox in includes/scripts.php; a card without one falls
   back to a plain link to settings.youtube_url and carries the "Coming
   Soon" badge below instead of pretending to be playable. */
.cgs-projects__video { padding-block: clamp(56px, 7vw, 96px); }
.cgs-projects__video-head { max-width: 62ch; margin: 0 0 clamp(28px, 3.5vw, 40px); }
.cgs-projects__video-head h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: #fff;
  text-wrap: balance;
}
.cgs-projects__video-head p { margin: 0; font-size: 16.5px; line-height: 1.7; color: rgba(255, 255, 255, 0.72); }

.cgs-projects__video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(20px, 2.5vw, 28px);
  margin: 0 0 clamp(28px, 3.5vw, 40px);
}
.cgs-projects__video-card {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: clamp(16px, 1.6vw, 20px);
  aspect-ratio: 4 / 3;
}
.cgs-projects__video-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 400ms var(--ease-out);
}
.cgs-projects__video-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 34, 56, 0.1) 0%, rgba(8, 34, 56, 0.68) 100%);
}
.cgs-projects__video-card:hover img { transform: scale(1.05); }
.cgs-projects__video-play {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(48px, 5vw, 60px);
  height: clamp(48px, 5vw, 60px);
  border-radius: 50%;
  background: #fff;
  color: var(--cgs-navy-900);
  font-size: 15px;
  transform: translate(-50%, -50%);
  transition: transform 220ms var(--ease-out);
}
.cgs-projects__video-play i { margin-left: 2px; }
.cgs-projects__video-card:hover .cgs-projects__video-play { transform: translate(-50%, -50%) scale(1.08); }
.cgs-projects__video-badge {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  padding: 5px 11px;
  border-radius: var(--cgs-radius);
  background: rgba(8, 34, 56, 0.55);
  backdrop-filter: blur(4px);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
.cgs-projects__video-title {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 14px;
  z-index: 1;
  color: #fff;
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.3;
}

/* --- Resources page --------------------------------------------------------
   Five DB-driven topics (database/schema.sql `resources` + `certificates`),
   read as one page in four visually distinct sections rather than one
   repeated accordion pattern: full document cards for Certificates (leads
   the page), a reference-card split for CBM/Freight Ton, a "big tabs"
   module for Incoterms/Insurance/Chargeable Weight (the client's own
   instruction — "I want to show big tabs" — 2026-08-14 email,
   docs/CONTENT.md), and a hairline document grid for Terms & Conditions/
   policy PDFs. */

/* --- Page banner: photo, title and breadcrumb only ------------------------
   Same absolute-media-behind-content technique as .cgs-hero (see that
   comment for why the photo is a separate positioned layer rather than a
   CSS background-image), just a fixed, much shorter box instead of a
   near-viewport-height carousel — this is an inner page, not the
   homepage. A navy gradient scrim sits between the photo and the text
   (client request, overriding DESIGN.md's No-Scrim Rule for this banner
   specifically) — darkest at the bottom, where the title and breadcrumb
   sit, fading out toward the top so the photo still reads clearly higher
   up in the frame. */
.cgs-page-banner {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(280px, 34vw, 560px);
  padding-block: clamp(28px, 4vw, 44px);
  background: var(--cgs-navy-900);
  color: #fff;
  overflow: hidden;
}
.cgs-page-banner__media { position: absolute; inset: 0; }
.cgs-page-banner__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Tug & Barge's banner photo (IMG_6109.JPG, 640x480, client-supplied
   2026-08-27) is a tall-ish action shot, not a wide banner-shaped one —
   object-fit: cover's default crop was hiding most of it in this very
   wide, short band. 2026-08-27 (client: "show full image not hide it"):
   scoped to this one page's banner rather than changed globally, since no
   other page's banner photo has been flagged — same object-fit: fill
   trade-off already applied to Our Fleet's Modular Trailers tile (full
   photo, no empty space, at the cost of a slight non-uniform stretch). */
body.page-tug-and-barge-chartering .cgs-page-banner__media img {
  object-fit: cover;
}
.cgs-page-banner::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(8, 34, 56, .2) 0%, rgba(8, 34, 56, .72) 100%);
  pointer-events: none;
}
.cgs-page-banner > .container-fluid { position: relative; z-index: 2; }
.cgs-page-banner h1 {
  margin: 0;
  color: #fff;
  text-shadow: 0 2px 14px rgba(8, 34, 56, .55), 0 1px 4px rgba(8, 34, 56, .4);
}
.cgs-page-banner__crumbs { margin: 0 0 14px; }
.cgs-page-banner__crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13.5px;
  font-weight: 600;
}
.cgs-page-banner__crumbs li {
  display: flex;
  align-items: center;
  gap: 8px;
  color: rgba(255, 255, 255, .8);
  text-shadow: 0 1px 8px rgba(8, 34, 56, .5);
}
.cgs-page-banner__crumbs li:not(:last-child)::after { content: '/'; opacity: .5; }
.cgs-page-banner__crumbs li[aria-current] { color: #fff; }
.cgs-page-banner__crumbs a {
  color: inherit;
  text-decoration: none;
  transition: color 180ms var(--ease-out);
}
.cgs-page-banner__crumbs a:hover,
.cgs-page-banner__crumbs a:focus-visible { color: #fff; }

/* --- Certificates: full document cards, not the homepage's small-badge
   strip. This page is where a buyer actually verifies our credentials, so
   each card shows the real scanned certificate (certificates.preview_image)
   plus issuer, certificate number and validity — the badge alone reused
   from the homepage undersold this section, per client feedback. */
.cgs-cert-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(24px, 3vw, 32px);
}
.cgs-cert-card {
  display: block;
  border-radius: var(--cgs-radius);
  overflow: hidden;
  /* box-shadow: var(--cgs-shadow); */
  transition: transform .25s ease, box-shadow .25s ease;
}
.cgs-cert-card:hover,
.cgs-cert-card:focus-visible {
  transform: translateY(-4px);
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-cert-card img {
  display: block;
  width: 100%;
  height: auto;
  /* aspect-ratio: 3 / 4; */
  object-fit: cover;
}

@media (max-width: 991.98px) {
  .cgs-cert-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
  .cgs-cert-grid { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .cgs-cert-card { transition: none; }
}

/* Rich text from resources.content (admin rich-text, sanitised on save —
   see CLAUDE.md Security). Shared by every DB-driven copy block on this
   page so a heading/list/table typed in the admin looks native to the
   design system without per-page CSS. */
.cgs-prose { max-width: 62ch; color: var(--cgs-slate); font-size: 15.5px; line-height: 1.75; }
.cgs-prose h3 {
  margin: 28px 0 12px;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--cgs-navy-900);
}
.cgs-prose h3:first-child { margin-top: 0; }
.cgs-prose p { margin: 0 0 14px; }
.cgs-prose ul { margin: 0 0 14px; padding-left: 20px; }
.cgs-prose li { margin-bottom: 6px; }
.cgs-prose strong { color: var(--cgs-ink); font-weight: 700; }
.cgs-prose table {
  width: 100%;
  margin: 8px 0 20px;
  border-collapse: collapse;
  font-size: 13.5px;
}
.cgs-prose caption {
  margin-bottom: 8px;
  text-align: left;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-prose th,
.cgs-prose td {
  padding: 10px 12px;
  border: 1px solid var(--cgs-line);
  text-align: left;
  vertical-align: top;
}
.cgs-prose th {
  background: var(--cgs-surface);
  font-weight: 700;
  color: var(--cgs-navy-900);
  white-space: nowrap;
}
/* Below 575.98px a 3-column reference table (e.g. the Incoterms table in
   the Shipping Essentials tabs) stops fitting the viewport at a readable
   size — rather than falling back to a horizontal-scroll slider, each row
   becomes its own card and each cell becomes a label/value line, using the
   cell's own data-label attribute (set in the resources.content HTML
   itself, e.g. <td data-label="Term">) as the label, so no JS is needed to
   read it off the hidden <thead>. Admin-authored tables without a
   data-label per cell just show an empty label rather than breaking. */
@media (max-width: 575.98px) {
  .cgs-prose table { display: block; }
  .cgs-prose thead { display: none; }
  .cgs-prose tbody { display: block; }
  .cgs-prose caption { margin-bottom: 12px; }
  .cgs-prose tr {
    display: block;
    margin-bottom: 12px;
    border: 1px solid var(--cgs-line);
    border-radius: var(--cgs-radius);
    overflow: hidden;
  }
  .cgs-prose tr:last-child { margin-bottom: 0; }
  .cgs-prose td {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    border: none;
    border-bottom: 1px solid var(--cgs-line);
    white-space: normal;
  }
  .cgs-prose td:last-child { border-bottom: none; }
  .cgs-prose td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    max-width: 40%;
    font-weight: 700;
    color: var(--cgs-navy-900);
  }
}

/* --- Cargo Measurement: stacked reading layout + ton converter -----------
   Redesigned 2026-08-25 (replacing the crate-diagram instrument panel):
   full-width intro, then "What is CBM" and "Understanding Freight Ton"
   side by side, then "How CBM and Freight Ton Work Together" beside the
   split-flap ("departure board") freight-ton converter, same two-column
   pattern as the row above it. resources.php splits the one admin-
   editable content blob on its <h3> boundaries to place each part — see
   the $cbmIntro/$cbmChunks comment there. */
.cgs-cbm {
  display: flex;
  flex-direction: column;
  gap: clamp(32px, 4vw, 48px);
}
.cgs-cbm__intro h2 { margin: 0 0 16px; }
.cgs-cbm__intro .cgs-prose,
.cgs-cbm__together > .cgs-prose { max-width: none; }
.cgs-cbm__split {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 56px);
}
.cgs-cbm__split::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: rgba(255, 255, 255, .16);
}
@media (max-width: 760px) {
  .cgs-cbm__split { grid-template-columns: 1fr; gap: 32px; }
  .cgs-cbm__split::before { display: none; }
}
.cgs-cbm__together {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: stretch;
}
@media (max-width: 760px) {
  .cgs-cbm__together { grid-template-columns: 1fr; gap: 24px; }
}
.cgs-cbm__together .cgs-converter {
  max-width: none;
  height: 100%;
  margin-top: 0;
  padding: clamp(24px, 3vw, 34px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
}

/* #cargo-measurement runs .cgs-section--dark — .cgs-prose is shared with
   the plain-white Shipping Essentials fallback leaf below, so its base
   colours stay light-mode and get overridden here, scoped to this section
   only, rather than changed globally. */
#cargo-measurement .cgs-prose { color: rgba(255, 255, 255, .74); }
#cargo-measurement .cgs-prose h3,
#cargo-measurement .cgs-prose strong { color: #fff; }

.cgs-converter {
  margin-top: 26px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--cgs-radius);
  padding: clamp(18px, 2.4vw, 22px);
}
.cgs-converter__label {
  font-family: var(--cgs-font);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
  margin-bottom: 12px;
}
.cgs-switch { display: inline-flex; padding: 3px; background: rgba(255, 255, 255, .08); border-radius: var(--cgs-radius); gap: 2px; }
.cgs-switch button {
  border: 0;
  background: transparent;
  padding: 9px 15px;
  font-size: 13px;
  font-weight: 700;
  color: rgba(255, 255, 255, .65);
  border-radius: 2px;
  cursor: pointer;
  transition: background .25s var(--ease-out), color .25s var(--ease-out);
}
.cgs-switch button.is-active { background: var(--cgs-cyan-400); color: var(--cgs-navy-900); }

.cgs-converter__readout { margin-top: 18px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.cgs-flapboard { display: inline-flex; gap: 5px; }
.cgs-flap {
  position: relative;
  min-width: 1em;
  padding: 9px 8px;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(255, 255, 255, .15);
  color: #EAF3FB;
  border-radius: 4px;
  font-family: var(--cgs-font);
  font-size: clamp(22px, 2.6vw, 27px);
  font-weight: 600;
  text-align: center;
  overflow: hidden;
}
.cgs-flap::after { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: rgba(0, 0, 0, .35); }
.cgs-flap span { display: inline-block; }
.cgs-flap.is-flipping span { animation: cgs-flapflip .26s ease; }
@keyframes cgs-flapflip {
  0%   { transform: scaleY(1);   opacity: 1; }
  48%  { transform: scaleY(.12); opacity: .3; }
  52%  { transform: scaleY(.12); opacity: .3; }
  100% { transform: scaleY(1);   opacity: 1; }
}
.cgs-converter__unit { font-size: 13px; color: rgba(255, 255, 255, .6); }
.cgs-converter__unit b { display: block; color: #fff; font-size: 14px; margin-bottom: 2px; }
.cgs-converter__formula { margin-top: 12px; font-family: var(--cgs-font); font-size: 12px; color: rgba(255, 255, 255, .4); }
.cgs-converter__formula b { color: rgba(255, 255, 255, .75); font-weight: 600; }

/* --- Shipping Essentials: manifest (Incoterms / Insurance / Weight) -------
   Redesigned 2026-08-25, replacing a top tab row + panel underneath. Three
   cargo-tag "leaves" sit edge to edge; the active one expands, the other
   two collapse to a 76px spine (icon + vertical title) you click to swap —
   see cgs.js for the flex-basis toggle. No fixed height anywhere: the row
   is display:flex with the browser's default align-items: stretch, so its
   height always tracks whichever leaf is actually open instead of a
   worst-case constant (this is also what keeps the Incoterms leaf, the
   tallest of the three, from forcing the other two tall as well). */
.cgs-manifest { display: flex; gap: 3px; align-items: stretch; }

.cgs-leaf {
  position: relative;
  background: var(--cgs-surface);
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
  flex: 0 0 72px;
  transition: flex-basis .55s var(--ease-in-out);
  display: flex;
  flex-direction: column;
}
.cgs-leaf.is-active { flex: 1 1 auto; background: #fff; }
/* Collapsed leaves must not render their body at all, on any viewport —
   left in flow (even narrowed to 72px) their real content (an 11-card
   grid, wrapped paragraphs) still lays out at full natural height, which
   flex's default align-items: stretch then imposes on the ACTIVE leaf too,
   this is what was making the whole manifest scroll far taller than the
   open panel's actual content. */
.cgs-leaf:not(.is-active) .cgs-leaf__body { display: none; }

.cgs-leaf__tab {
  all: unset;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  color: var(--cgs-ink);
}
.cgs-leaf:not(.is-active) .cgs-leaf__tab {
  flex-direction: column;
  justify-content: flex-start;
  text-align: center;
  height: 100%;
  padding-top: 20px;
  gap: 12px;
}
.cgs-leaf__icon {
  flex-shrink: 0;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  color: var(--cgs-cyan-300);
  font-size: 13px;
}
.cgs-leaf__title { font-weight: 700; font-size: 15.5px; }
.cgs-leaf__title-short {
  display: none;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--cgs-slate);
}
/* Collapsed: short vertical label only — the full title (which can run
   long, e.g. "Freight Service Liability Insurance versus Cargo Insurance")
   would otherwise need more height than the actually-open leaf's real
   content, and since the row height tracks the tallest leaf, that long
   collapsed title would quietly become the thing setting the row's height
   instead of whatever's open. */
.cgs-leaf:not(.is-active) .cgs-leaf__title { display: none; }
.cgs-leaf:not(.is-active) .cgs-leaf__title-short { display: block; }
.cgs-leaf.is-active .cgs-leaf__tab { border-bottom: 1px solid var(--cgs-line); }

.cgs-leaf__body { padding: clamp(16px, 2.2vw, 26px); flex: 1; }
.cgs-leaf__body-inner { opacity: 0; transform: translateY(10px); }
.cgs-leaf.is-active .cgs-leaf__body-inner { animation: cgs-leaf-in .5s var(--ease-out) .12s forwards; }
@keyframes cgs-leaf-in { to { opacity: 1; transform: translateY(0); } }
.cgs-leaf__intro { font-size: 13.5px; color: var(--cgs-slate); line-height: 1.65; max-width: 66ch; margin: 0 0 12px; }

/* Mobile: a real tab row (all three side by side), not the desktop
   fan-of-columns — a rotated vertical title stacked three-high doesn't
   work at phone width. `display: contents` on .cgs-leaf unwraps it so its
   __tab and __body become direct flex children of .cgs-manifest; every
   tab then gets `order: 0` and an equal third of the row, every body gets
   `order: 1` and `flex-basis: 100%` so the one visible body (the other
   two stay display:none) always falls onto its own full-width row right
   below the tab strip, in normal document flow — no absolute positioning,
   no JS involved. Because .cgs-leaf itself no longer paints a box, its
   card chrome (background/border) moves onto __tab and __body directly. */
@media (max-width: 860px) {
  .cgs-manifest { flex-wrap: wrap; }
  .cgs-leaf { display: contents; }

  .cgs-leaf__tab {
    order: 0;
    flex: 1 1 0;
    flex-direction: column !important;
    align-items: center;
    justify-content: center;
    height: auto !important;
    gap: 6px;
    padding: 12px 6px;
    text-align: center;
    background: var(--cgs-surface);
    border: 1px solid var(--cgs-line);
    border-radius: var(--cgs-radius);
  }
  .cgs-leaf.is-active .cgs-leaf__tab {
    background: var(--cgs-navy-900);
    border-color: var(--cgs-navy-900);
    border-bottom: none;
    color: #fff;
  }
  .cgs-leaf__title,
  .cgs-leaf__title-short { font-size: 11.5px; }
  .cgs-leaf__title { display: none; }
  .cgs-leaf__title-short {
    display: block;
    writing-mode: horizontal-tb;
    transform: none;
    color: inherit;
  }

  .cgs-leaf__body {
    order: 1;
    flex: 1 1 100%;
    margin-top: 3px;
    background: #fff;
    border: 1px solid var(--cgs-line);
    border-radius: var(--cgs-radius);
  }
}

/* Incoterms: static card grid instead of a <table>, grouped exactly as the
   admin copy describes — "any mode" vs "sea and inland waterway only".
   Each card shows the code, name and risk-transfer point together — no
   click/flip needed to read it. */
.cgs-iterm-group + .cgs-iterm-group { margin-top: 12px; }
.cgs-iterm-group__label {
  display: flex; align-items: center; gap: 7px;
  font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--cgs-muted); margin: 0 0 6px;
}
.cgs-iterm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.cgs-iterm-card {
  background: var(--cgs-navy-900);
  color: #fff;
  border-radius: var(--cgs-radius);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.cgs-iterm-code { font-size: 15px; font-weight: 700; letter-spacing: .01em; }
.cgs-iterm-name { font-size: 10.5px; color: rgba(255, 255, 255, .55); }
.cgs-iterm-risk { font-size: 10.5px; line-height: 1.35; color: rgba(255, 255, 255, .8); margin-top: 2px; }

/* Liability vs Cargo Insurance: a VS split instead of a paragraph. */
.cgs-vs-split {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-vs-side {
  background: #fff;
  padding: clamp(18px, 2.6vw, 24px);
  opacity: 0;
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
}
.cgs-vs-side--a { transform: translateX(-14px); }
.cgs-vs-side--b { transform: translateX(14px); }
.cgs-leaf.is-active .cgs-vs-side { opacity: 1; transform: translateX(0); }
.cgs-leaf.is-active .cgs-vs-side--b { transition-delay: .12s; }
.cgs-vs-side h4 { font-size: 15px; font-weight: 800; margin: 12px 0 10px; color: var(--cgs-ink); }
.cgs-vs-side ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.cgs-vs-side li { display: flex; gap: 8px; font-size: 13px; color: var(--cgs-slate); line-height: 1.5; }
.cgs-vs-side li i { flex-shrink: 0; margin-top: 3px; font-size: 11px; color: var(--cgs-cyan-400); }
.cgs-vs-icon {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--cgs-surface);
  border: 1px solid var(--cgs-line);
  color: var(--cgs-blue-500);
  font-size: 13px;
}
.cgs-vs-badge {
  position: absolute; left: 50%; top: 26px; transform: translateX(-50%);
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--cgs-navy-900); color: #fff;
  display: grid; place-items: center;
  font-family: var(--cgs-font); font-size: 10.5px; font-weight: 600;
  box-shadow: var(--cgs-shadow);
  z-index: 1;
}
.cgs-vs-note { grid-column: 1 / -1; background: var(--cgs-surface); padding: 14px 20px; font-size: 12.5px; color: var(--cgs-slate); border-top: 1px solid var(--cgs-line); }
@media (max-width: 620px) {
  .cgs-vs-split { grid-template-columns: 1fr; }
  .cgs-vs-side--a { order: 1; }
  .cgs-vs-badge {
    position: static;
    order: 2;
    justify-self: center;
    margin: -19px 0;
  }
  .cgs-vs-side--b { order: 3; }
  .cgs-vs-note { order: 4; }
}

/* Chargeable weight: live L/W/H sliders racing an actual-vs-volumetric bar. */
.cgs-calc-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: clamp(22px, 3vw, 36px); align-items: start; }
@media (max-width: 720px) { .cgs-calc-grid { grid-template-columns: 1fr; } }
.cgs-slider-row { margin-bottom: 16px; }
.cgs-slider-row:last-of-type { margin-bottom: 0; }
.cgs-slider-row__label { display: flex; justify-content: space-between; font-size: 12.5px; color: var(--cgs-slate); margin-bottom: 7px; }
.cgs-slider-row__label b { font-family: var(--cgs-font); color: var(--cgs-ink); font-weight: 600; }
.cgs-slider-row__u { font-family: var(--cgs-font); color: var(--cgs-muted); }
.cgs-calc-note { margin: 14px 0 0; font-family: var(--cgs-font); font-size: 12px; color: var(--cgs-muted); }

.cgs-manifest input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; border-radius: 2px;
  background: var(--cgs-line); outline: none; cursor: pointer;
}
.cgs-manifest input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--cgs-cyan-400); border: 3px solid var(--cgs-navy-900); cursor: grab;
}
.cgs-manifest input[type="range"]::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--cgs-cyan-400); border: 3px solid var(--cgs-navy-900); cursor: grab;
}

.cgs-race { display: flex; flex-direction: column; gap: 14px; }
.cgs-race-row__head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.cgs-race-row__name { font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--cgs-muted); font-family: var(--cgs-font); }
.cgs-race-row__val { display: flex; align-items: center; gap: 8px; }
.cgs-race-num { font-family: var(--cgs-font); font-variant-numeric: tabular-nums; font-size: 13px; color: var(--cgs-ink); }
.cgs-race-track { height: 28px; background: var(--cgs-surface); border: 1px solid var(--cgs-line); border-radius: 3px; overflow: hidden; }
.cgs-race-fill { height: 100%; width: 0%; background: var(--cgs-navy-700); transition: width .4s var(--ease-out), background .3s; border-radius: 2px 0 0 2px; }
.cgs-race-fill.is-winner { background: var(--cgs-cyan-400); }
.cgs-chargeable-pill {
  font-family: var(--cgs-font); font-size: 10px; font-weight: 600; letter-spacing: .05em;
  background: var(--cgs-cyan-400); color: var(--cgs-navy-900); padding: 2px 7px; border-radius: 20px;
  opacity: 0; transform: scale(.7); transition: opacity .25s, transform .25s;
}
.cgs-chargeable-pill.is-shown { opacity: 1; transform: scale(1); }

/* --- Terms & Conditions / policy documents --------------------------------
   Same hairline-grid technique as .cgs-desk__grid (1px background showing
   through as dividers), sized for a file link instead of a contact card. */
.cgs-docs__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--cgs-line);
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-docs__grid li { background: #fff; }
.cgs-docs__link {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
  padding: 24px 22px;
  color: inherit;
  text-decoration: none;
  transition: background-color 180ms var(--ease-out);
}
.cgs-docs__link:hover,
.cgs-docs__link:focus-visible { background: var(--cgs-surface); }
.cgs-docs__icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-blue-500);
  font-size: 16px;
}
.cgs-docs__link:hover .cgs-docs__icon,
.cgs-docs__link:focus-visible .cgs-docs__icon { background: #fff; }
.cgs-docs__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--cgs-navy-900);
  line-height: 1.35;
}
.cgs-docs__desc { margin: 0; font-size: 13px; line-height: 1.55; color: var(--cgs-muted); }
.cgs-docs__meta {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-docs__link:hover .cgs-docs__meta i,
.cgs-docs__link:focus-visible .cgs-docs__meta i { transform: translateX(3px); }
.cgs-docs__meta i { transition: transform 180ms var(--ease-out); }

@media (max-width: 991.98px) {
  .cgs-docs__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
  .cgs-docs__grid { grid-template-columns: 1fr; }
}

/* Corner watermark, same masked-raster technique as .cgs-desk::after (see
   that comment for the full rationale) — reused here top-left and in navy
   rather than bottom-right and blue, so the two instances of the same
   motif read as a family, not a copy-paste repeat. */
.cgs-terms { position: relative; overflow: hidden; }
.cgs-terms::after {
  content: '';
  position: absolute;
  z-index: 0;
  right: clamp(-10px, 1.5vw, 12px);
  bottom: 0;
  width: clamp(200px, 24vw, 380px);
  aspect-ratio: 1000 / 893;
  background-color: var(--cgs-blue-500);
  opacity: .08;
  -webkit-mask-image: url("../img/bg/oil-rig-illustration.png");
          mask-image: url("../img/bg/oil-rig-illustration.png");
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: bottom right;
          mask-position: bottom right;
  -webkit-mask-size: contain;
          mask-size: contain;
  pointer-events: none;
}
.cgs-terms > .container-fluid { position: relative; z-index: 1; }

/* --- Scroll reveal -------------------------------------------------------
   cgs.js adds .is-visible via IntersectionObserver. The initial state only
   applies when JS is present (html.js), so a no-JS visitor sees the content
   rather than a blank page. */

html.js [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
}
html.js [data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 520ms var(--ease-out) var(--reveal-delay, 0ms),
              transform 520ms var(--ease-out) var(--reveal-delay, 0ms);
}

/* --- Reduced motion ------------------------------------------------------
   Not "no animation": opacity and colour still aid comprehension. What goes
   is movement, scaling and anything that travels across the screen. */

@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal] { opacity: 1; transform: none; }
  html.js .cgs-split__media img { opacity: 1; transform: none; transition: none; }
  .cgs-mobile-panel { transition: opacity 120ms ease, visibility 120ms; transform: none; }
  .cgs-mobile-panel.is-open { transform: none; }
  .cgs-burger:active { transform: none; }
  .cgs-btn:hover,
  .cgs-btn:active,
  .cgs-service-card:hover,
  .cgs-service-card:active,
  .cgs-services__arrow:active { transform: none; }
  .cgs-service-card:hover .cgs-service-card__media img { transform: none; }
  .cgs-service-bento__cta:hover i,
  .cgs-service-bento__cta:hover .cgs-service-bento__cta-media img { transform: none; }
  .cgs-btn:hover i,
  .cgs-textlink:hover i,
  .cgs-topbar__contact:hover i { transform: none; }
  .cgs-docs__link:hover .cgs-docs__meta i,
  .cgs-docs__link:focus-visible .cgs-docs__meta i { transform: none; }

  /* Shipping Essentials manifest — the flip and slide motions are all
     decorative sequencing; drop them and show the end state immediately.
     Values (split-flap digits, calculator bars) still update, just
     without the travel. */
  .cgs-flap.is-flipping span { animation: none; }
  .cgs-leaf__body-inner { opacity: 1; transform: none; animation: none; }
  .cgs-vs-side { opacity: 1 !important; transform: none !important; transition: none; }
  .cgs-leaf { transition: none; }
}

/* --- Focus visibility ---------------------------------------------------- */

:where(a, button, input, select, textarea):focus-visible {
  outline: 3px solid var(--cgs-cyan-400);
  outline-offset: 2px;
}

/* --- 404 ------------------------------------------------------------------- */

.cgs-404 {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  background: var(--cgs-navy-900);
  color: #fff;
  padding-block: clamp(96px, 14vw, 160px);
}
.cgs-404__inner { max-width: 640px; }
.cgs-404__inner h1 {
  margin: 12px 0 20px;
  font-size: clamp(32px, 4.6vw, 52px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.025em;
  color: #fff;
  text-wrap: balance;
}
.cgs-404__inner > p {
  margin: 0 0 32px;
  max-width: 52ch;
  font-size: 17px;
  line-height: 1.7;
  color: rgba(255, 255, 255, .68);
}
/* In-copy link on the dark 404/thank-you panel — the global `a` rule's
   --cgs-blue-500 is unreadable on this navy background. */
.cgs-404__inline-link { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
.cgs-404__inline-link:hover { color: var(--cgs-cyan-300); }
.cgs-404__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-bottom: 48px; }

.cgs-404__links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  margin: 0;
  padding-top: 28px;
  border-top: 1px solid rgba(255, 255, 255, .16);
  list-style: none;
}
.cgs-404__links a {
  font-size: 14.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, .78);
  text-decoration: none;
}
.cgs-404__links a:hover { color: var(--cgs-cyan-300); }

@media (max-width: 767.98px) {
  .cgs-404__actions .cgs-btn { width: 100%; justify-content: center; }
}

/* --- Contact: reach split (photo + form) -----------------------------------
   Asymmetric 5fr/7fr (DESIGN.md: never an even 1fr/1fr) — a real ops photo
   left (assets/img/gallery/ops-18.jpg), the enquiry form right. */
.cgs-reach {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.cgs-reach__media { position: relative; }
.cgs-reach__photo {
  border-radius: var(--cgs-radius);
  overflow: hidden;
  background: var(--cgs-line);
  box-shadow: var(--cgs-shadow);
}
.cgs-reach__photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}
.cgs-form__head { max-width: 60ch; margin: 0 0 28px; }
.cgs-form__head h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3vw, 36px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-form__head p { margin: 0; font-size: 16.5px; line-height: 1.7; color: var(--cgs-slate); }

.cgs-form__alert {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 24px;
  padding: 14px 18px;
  border-radius: var(--cgs-radius);
  border: 1px solid rgba(214, 69, 80, .3);
  background: rgba(214, 69, 80, .06);
  color: var(--cgs-danger);
  font-size: 14px;
  line-height: 1.55;
}
.cgs-form__alert i { margin-top: 2px; flex-shrink: 0; }

.cgs-field-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
.cgs-field { display: flex; flex-direction: column; gap: 8px; }
.cgs-field--full { grid-column: 1 / -1; }
.cgs-field label { font-size: 13px; font-weight: 600; color: var(--cgs-ink); }
.cgs-field label .req { color: var(--cgs-danger); margin-left: 2px; }
.cgs-field input,
.cgs-field select,
.cgs-field textarea {
  width: 100%;
  padding: 13px 16px;
  border: 1.5px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  background: #fff;
  font-family: var(--cgs-font);
  font-size: 14.5px;
  color: var(--cgs-ink);
  transition: border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}
.cgs-field textarea { resize: vertical; min-height: 120px; }
.cgs-field input:focus,
.cgs-field select:focus,
.cgs-field textarea:focus {
  outline: none;
  border-color: var(--cgs-cyan-400);
  box-shadow: 0 0 0 4px rgba(46, 159, 214, .14);
}
/* Honeypot: off-screen, not display:none — screen readers and bots that
   check computed visibility both still see it as "there", real bots that
   fill every field trip it. Checked in submit-lead.php. */
.cgs-field--trap {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.cgs-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: 24px;
}
.cgs-form__note {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--cgs-muted);
}
.cgs-form__note i { color: var(--cgs-success); }

@media (max-width: 991.98px) {
  .cgs-reach { grid-template-columns: 1fr; }
  .cgs-reach__photo img { aspect-ratio: 16 / 10; }
  .cgs-reach__media { margin-bottom: 44px; } /* room for the badge's overlap */
}
@media (max-width: 575.98px) {
  .cgs-field-grid { grid-template-columns: 1fr; }
  .cgs-form__foot .cgs-btn { width: 100%; justify-content: center; }
}

/* --- Contact: offices + map -------------------------------------------------
   Asymmetric 7fr/5fr — real SG + MY office cards left, a sticky stack of
   two map embeds right (.cgs-map-stack), one per office, each labelled so
   it's clear which pin is which. settings.map_embed_url / my_map_embed_url
   (client-supplied Google Maps embed URLs, 2026-08-24) drive the real
   iframes; either falls back independently to a placeholder (dot-grid
   ground, same decoration technique as .cgs-video-band, plus a pin) with a
   real "Get Directions" link if its embed URL is ever unset again — see
   contact.php. */
.cgs-offices-band__heading,
.cgs-touch__heading {
  margin: 4px 0 clamp(28px, 3.5vw, 40px);
  font-size: clamp(26px, 3.4vw, 38px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-offices {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.cgs-office-list { display: flex; flex-direction: column; gap: 20px; }
.cgs-office-card {
  position: relative;
  padding: clamp(24px, 3vw, 30px) clamp(24px, 3vw, 28px);
  border-radius: var(--cgs-radius);
  background: #fff;
  border: 1px solid var(--cgs-line);
  box-shadow: var(--cgs-shadow);
  overflow: hidden;
}
.cgs-office-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--cgs-cyan-400);
}
.cgs-office-card__flag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--cgs-blue-500);
}
.cgs-office-card h3 { margin: 0 0 4px; font-size: 19px; font-weight: 800; color: var(--cgs-navy-900); }
.cgs-office-card__reg { margin: 0 0 16px; font-size: 12.5px; color: var(--cgs-muted); }
.cgs-office-card__meta { margin: 0 0 18px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 10px; }
.cgs-office-card__meta li { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; line-height: 1.55; color: var(--cgs-slate); }
.cgs-office-card__meta i { margin-top: 3px; flex-shrink: 0; width: 13px; color: var(--cgs-cyan-400); font-size: 13px; }
.cgs-office-card__meta a { color: inherit; text-decoration: none; }
.cgs-office-card__meta a:hover { color: var(--cgs-blue-500); }
.cgs-office-card__soon { color: var(--cgs-muted); font-style: italic; }
.cgs-office-card__soon i { color: var(--cgs-muted) !important; }
.cgs-office-card__directions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--cgs-navy-900);
  text-decoration: none;
}
.cgs-office-card__directions i { font-size: 11px; transition: transform 200ms var(--ease-out); }
.cgs-office-card__directions:hover i { transform: translateX(3px); }

.cgs-map-stack {
  position: sticky;
  top: calc(var(--cgs-header-h, 80px) + 24px);
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.cgs-map-card {
  position: relative;
  border-radius: var(--cgs-radius);
  background: var(--cgs-navy-900);
  box-shadow: var(--cgs-shadow);
  overflow: hidden;
}
.cgs-map-card--embed { min-height: 280px; }
.cgs-map-card--embed iframe { display: block; width: 100%; height: 100%; min-height: 280px; border: 0; }
.cgs-map-card__label {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 1;
  margin: 0;
  padding: 6px 12px;
  border-radius: var(--cgs-radius);
  background: rgba(8, 34, 56, 0.72);
  backdrop-filter: blur(4px);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.cgs-map-card__placeholder {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  min-height: 360px;
  padding: 40px 32px;
  text-align: center;
}
.cgs-map-card__placeholder::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, .14) 1px, transparent 1px);
  background-size: 24px 24px;
  pointer-events: none;
}
.cgs-map-card__pin {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--cgs-cyan-400);
  color: #fff;
  font-size: 20px;
  box-shadow: 0 10px 30px rgba(46, 159, 214, .4);
}
.cgs-map-card__placeholder p { position: relative; z-index: 1; margin: 0; max-width: 30ch; font-size: 15px; line-height: 1.6; color: rgba(255, 255, 255, .68); }
.cgs-map-card__placeholder strong { color: #fff; font-size: 15.5px; }

@media (max-width: 991.98px) {
  .cgs-offices { grid-template-columns: 1fr; }
  .cgs-map-stack { position: static; }
}

/* --- Contact: "other ways to reach us" --------------------------------------
   Hairline 1px-gap grid, the same technique as the homepage's Project Desk
   directory (.cgs-desk__grid) but built for contact-method tiles instead of
   named people. WhatsApp has no number configured yet, so that tile renders
   muted with a "coming soon" label instead of a dead wa.me link. */
/* Flexbox, not grid: the tile count varies (3 to 5, depending on which
   settings are configured — see contact.php), and a grid with a fixed
   column count leaves dead cells showing the container's own hairline
   background whenever the last row doesn't fill every column. Flex items
   always fill the row they're in, so there's no dead-cell case to guard
   against. */
.cgs-touch__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  background: var(--cgs-line);
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-touch__item {
  flex: 1 1 210px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 28px 24px;
  background: #fff;
}
.cgs-touch__icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-cyan-400);
  font-size: 15px;
}
.cgs-touch__item--muted .cgs-touch__icon { color: var(--cgs-muted); }
.cgs-touch__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--cgs-muted);
}
.cgs-touch__value { font-size: 15px; font-weight: 700; color: var(--cgs-navy-900); text-decoration: none; }
.cgs-touch__value:hover { color: var(--cgs-blue-500); }
.cgs-touch__soon { font-size: 13.5px; font-style: italic; color: var(--cgs-muted); }
.cgs-touch__socials { display: flex; gap: 10px; margin-top: 2px; }
.cgs-touch__socials a {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-navy-900);
  transition: background-color 180ms var(--ease-out), color 180ms var(--ease-out);
}
.cgs-touch__socials a:hover { background: var(--cgs-navy-900); color: #fff; }

@media (max-width: 575.98px) { .cgs-touch__item { flex-basis: 100%; } }

/* =============================================================================
   Our Fleet page (our-fleet.php)
   -----------------------------------------------------------------------------
   Content is Angeline Tilokani's corrected "Our Fleet.docx" (25 Aug 2026) —
   see our-fleet.php's header comment. Four sections below: the asymmetric
   equipment showcase, the dark connected Port & Terminal row, the two
   plotted-route Transhipment cards, and the existing .cgs-split reused for
   Lashing.
   ========================================================================== */

/* --- Intro -------------------------------------------------------------
   Text and image columns share one grid track size, so the right-hand
   photo is locked to the exact width and height of the text column
   rather than sized to its own content. */
.cgs-fleet-intro__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: clamp(28px, 4vw, 56px);
}
.cgs-fleet-intro__text { display: flex; flex-direction: column; justify-content: center; }
.cgs-fleet-intro__inner h2 {
  margin: 0 0 18px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cgs-fleet-intro__prose p { margin: 0 0 16px; }
.cgs-fleet-intro__prose p:last-child { margin-bottom: 0; }
.cgs-fleet-intro__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  min-height: 320px;
}
.cgs-fleet-intro__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 767.98px) {
  .cgs-fleet-intro__inner { grid-template-columns: 1fr; }
  .cgs-fleet-intro__media { min-height: 240px; order: -1; }
}

/* --- Specialized Fleet & Infrastructure: bento showcase --------------------
   Five items, five cells, no empty space: Modular Trailers leads wide
   (nth-child(1)) since the SPMT photo is the strongest equipment match in
   the asset set, Skeleton Chassis sits beside it, then Low Bed, Forklifts
   and Open Storage Yard share the row underneath — the two icon cells
   (no photo exists for either) sit inline with that row rather than in
   their own separate strip. Order is driven entirely by fleet_items.sort_order
   (see schema.sql), not by markup position. */
.cgs-fleet-bento__head { max-width: 640px; margin: 0 0 clamp(32px, 4vw, 48px); }
.cgs-fleet-bento__head h2 {
  margin: 0 0 10px;
  font-size: clamp(24px, 2.8vw, 32px);
  font-weight: 800;
  letter-spacing: -0.02em;
}
.cgs-fleet-bento__head p { margin: 0; color: var(--cgs-slate); font-size: 16.5px; line-height: 1.7; }

.cgs-fleet-bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 2vw, 20px);
}
.cgs-fleet-bento .cgs-fleet-tile:nth-child(1) { grid-column: span 2; min-height: 440px; }
/* Modular Trailers' source photo (fleet-cable-reel-chassis.jpg) has the
   "CARRIAGE GLOBAL (S) PTE LTD" text painted along the very bottom edge of
   the trailer bed — object-fit: cover was cropping into that band (or, once
   bottom-anchored, crowding it against the caption gradient) because cover
   always fills the box and sacrifices whatever doesn't fit. 2026-08-27
   (client: "show full image like contain does", then "stretch to fill the
   section" once contain's letterbox bars showed): object-fit: fill —
   stretches the photo non-uniformly to exactly fill the tile, so nothing is
   cropped AND there are no empty bars. The photo's 16:9 is a bit wider than
   the tile's ~2.4:1, so this does stretch it slightly taller than its
   native proportions — a deliberate trade the client asked for over either
   cropping or letterboxing. */
.cgs-fleet-bento .cgs-fleet-tile:nth-child(1) img {
  object-fit: fill;
}

.cgs-fleet-tile {
  position: relative;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  min-height: 340px;
  display: flex;
  align-items: flex-end;
}
.cgs-fleet-tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
.cgs-fleet-tile:hover img,
.cgs-fleet-tile:focus-within img { transform: scale(1.045); }
.cgs-fleet-tile::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Softened 2026-08-27 (client: several of these photos carry the CGS
     name/tel printed on the trailer itself, low in frame — the old 35%
     start plus a near-opaque .82 peak buried that branding under the
     caption instead of just backing the caption text. Lower peak opacity
     + a stronger text-shadow below keeps the caption legible while
     letting the branding underneath still read through. */
  background: linear-gradient(180deg, rgba(8, 34, 56, 0) 45%, rgba(8, 34, 56, .58) 100%);
}
.cgs-fleet-tile__body { position: relative; z-index: 1; padding: 20px 22px; color: #fff; }
.cgs-fleet-tile__body h3 {
  margin: 0 0 6px;
  font-size: 18px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 6px rgba(0, 0, 0, .55);
}
.cgs-fleet-tile__body p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: rgba(255, 255, 255, .85);
  max-width: 42ch;
  text-shadow: 0 1px 5px rgba(0, 0, 0, .5);
}
.cgs-fleet-tile__specs { margin: 12px 0 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.cgs-fleet-tile__specs li {
  font-family: var(--cgs-font);
  font-size: 11px;
  letter-spacing: .04em;
  padding: 4px 10px;
  border-radius: 100px;
  background: rgba(255, 255, 255, .14);
  border: 1px solid rgba(255, 255, 255, .24);
  color: #fff;
}
/* 2026-08-27 (client: "hide the description in all cards, only show on
   hover"): the title stays put as a permanent label on the photo, but the
   description (and the spec pills below it, which read as orphaned once
   the sentence explaining them is gone) collapse to nothing and fade/slide
   in together on hover or keyboard focus. max-height (not display/height)
   is what's animatable here — 120px is comfortably more than this text
   ever needs, so it never visibly clips before the height transition
   finishes. Comes after the base h3/p/specs rules above so its
   margin-top: 0 wins the cascade without needing !important. */
.cgs-fleet-tile__body p,
.cgs-fleet-tile__specs {
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 350ms var(--ease-out), opacity 220ms ease, margin-top 350ms var(--ease-out);
}
.cgs-fleet-tile:hover .cgs-fleet-tile__body p,
.cgs-fleet-tile:focus-within .cgs-fleet-tile__body p,
.cgs-fleet-tile:hover .cgs-fleet-tile__specs,
.cgs-fleet-tile:focus-within .cgs-fleet-tile__specs {
  max-height: 120px;
  opacity: 1;
  margin-top: 12px;
}

.cgs-fleet-tile--icon {
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  padding: 26px 24px;
  background: #fff;
  border: 1px solid var(--cgs-line);
}
/* No photo behind this variant, so the caption-legibility gradient (which
   every plain .cgs-fleet-tile gets via ::after) has nothing to sit on top
   of — left enabled, it painted a stray dark smear over the white card.
   First actually rendered 2026-08-27 when Forklifts/Open Storage Yard
   switched to this fallback (see schema.sql's fleet_items comment). */
.cgs-fleet-tile--icon::after { content: none; }
.cgs-fleet-tile__icon {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-bottom: 14px;
  border-radius: 50%;
  background: var(--cgs-surface);
  color: var(--cgs-cyan-400);
  font-size: 19px;
  flex: none;
}
.cgs-fleet-tile--icon h3 { margin: 0 0 8px; font-size: 17px; font-weight: 800; color: var(--cgs-ink); }
.cgs-fleet-tile--icon p { margin: 0; font-size: 15px; line-height: 1.6; color: var(--cgs-slate); }

@media (max-width: 767.98px) {
  .cgs-fleet-bento { grid-template-columns: 1fr; }
  .cgs-fleet-bento .cgs-fleet-tile:nth-child(1) { grid-column: span 1; min-height: 300px; }
}

/* --- Port & Terminal Operations: dark connected row -------------------------
   A process, not a product — no equipment photo would fit honestly here,
   so the three nodes sit on a hairline rail instead. Real container-
   terminal photography (oocl-pipe-trailer.jpg, shot beside OOCL boxes)
   dimmed well back behind it, in place of a stock icon watermark, since
   real photography exists for this section specifically. */
.cgs-port-ops { position: relative; overflow: hidden; }
.cgs-port-ops__media { position: absolute; inset: 0; z-index: 0; }
.cgs-port-ops__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(.65) brightness(.4);
}
.cgs-port-ops__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 34, 56, .9), rgba(8, 34, 56, .95));
}
.cgs-port-ops > .container-fluid { position: relative; z-index: 1; }

.cgs-port-ops__head { max-width: 640px; margin: 0 auto clamp(40px, 5vw, 60px); text-align: center; }
.cgs-port-ops__head h2 { margin: 0 0 10px; font-size: clamp(24px, 2.8vw, 32px); font-weight: 800; }
.cgs-port-ops__head p { margin: 0; color: rgba(255, 255, 255, .72); font-size: 16.5px; line-height: 1.7; }

.cgs-port-ops__row {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(24px, 3vw, 40px);
}
.cgs-port-ops__row::before {
  content: '';
  position: absolute;
  top: 27px;
  left: calc(100% / 6);
  right: calc(100% / 6);
  height: 1px;
  background: rgba(46, 159, 214, .28);
}
.cgs-port-node { position: relative; text-align: center; padding: 0 12px; }
.cgs-port-node__icon {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(46, 159, 214, .4);
  color: var(--cgs-cyan-300);
  font-size: 18px;
}
.cgs-port-node h3 { margin: 0 0 8px; font-size: 17px; font-weight: 800; color: #fff; }
.cgs-port-node p { margin: 0; font-size: 15px; line-height: 1.65; color: rgba(255, 255, 255, .7); }

@media (max-width: 767.98px) {
  .cgs-port-ops__row { grid-template-columns: 1fr; gap: 28px; }
  .cgs-port-ops__row::before { display: none; }
}

/* --- Regional Transhipment Services: plotted-route cards --------------------
   Two small route diagrams instead of another card grid — the shape of
   each lane (a short hop to Batam, a longer overland run through Malaysia
   to Thailand) is the point, so it is drawn rather than described. */
.cgs-transhipment__head { max-width: 640px; margin: 0 0 clamp(32px, 4vw, 48px); }
.cgs-transhipment__head h2 { margin: 0 0 10px; font-size: clamp(24px, 2.8vw, 32px); font-weight: 800; }
.cgs-transhipment__head p { margin: 0; color: var(--cgs-slate); font-size: 16.5px; line-height: 1.7; }

.cgs-route-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(20px, 3vw, 32px);
}
.cgs-route-card {
  position: relative;
  overflow: hidden;
  padding: clamp(26px, 3vw, 34px) clamp(24px, 3vw, 30px);
  border-radius: var(--cgs-radius);
  min-height: 260px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.cgs-route-card__media { position: absolute; inset: 0; z-index: 0; }
.cgs-route-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
.cgs-route-card:hover .cgs-route-card__media img,
.cgs-route-card:focus-within .cgs-route-card__media img { transform: scale(1.045); }
.cgs-route-card__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 34, 56, .55) 0%, rgba(8, 34, 56, .9) 100%);
}
.cgs-route-card__svg,
.cgs-route-card__stops,
.cgs-route-card h3,
.cgs-route-card p { position: relative; z-index: 1; }
.cgs-route-card__svg { display: block; width: 100%; height: 20px; margin-bottom: 16px; overflow: visible; }
.cgs-route-card__path { stroke: var(--cgs-cyan-400); stroke-width: 2; fill: none; }
.cgs-route-card__dot { fill: var(--cgs-navy-900); stroke: var(--cgs-cyan-400); stroke-width: 2; }
.cgs-route-card__stops {
  display: flex;
  justify-content: space-between;
  margin: 0 0 20px;
  font-family: var(--cgs-font);
  font-size: 11.5px;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .75);
}
.cgs-route-card h3 { margin: 0 0 8px; font-size: 18px; font-weight: 800; letter-spacing: -0.01em; color: #fff; }
.cgs-route-card p { margin: 0; font-size: 15.5px; line-height: 1.7; color: rgba(255, 255, 255, .82); }

/* Draw-in piggybacks on the shared [data-reveal] mechanism in cgs.js — the
   wrapping .cgs-route-cards already carries data-reveal, so no
   page-specific script is needed. Scoped to html.js exactly like every
   other [data-reveal] rule, so a no-JS visitor gets the line fully drawn
   rather than permanently hidden. The second line of the Malaysia/Thailand
   card carries its own --path-delay so that hop draws in a beat after the
   first, reading as two legs of one journey instead of one flat wipe. */
html.js .cgs-route-card__path {
  stroke-dasharray: 210;
  stroke-dashoffset: 210;
  transition: stroke-dashoffset 900ms var(--ease-in-out) var(--path-delay, 0ms);
}
html.js [data-reveal].is-visible .cgs-route-card__path { stroke-dashoffset: 0; }

@media (prefers-reduced-motion: reduce) {
  .cgs-route-card__path { transition-duration: 0ms; }
}

@media (max-width: 767.98px) {
  .cgs-route-cards { grid-template-columns: 1fr; }
}

/* =============================================================================
   Heavy Lift Chartering page (heavy-lift-chartering.php)
   -----------------------------------------------------------------------------
   Content is the client's "Breakbulk chartering -1 pics" email (Angeline
   Tilokani, 14 Aug 2026), transcribed verbatim in docs/CONTENT.md ("Service
   page 2"). Five section families below, none repeated: an intro split, a
   full-bleed statement band, a vertical connected process rail (the 7-step
   "How Tailored Vessel Solutions Work" list), an asymmetric capability
   bento (the four discrete capabilities buried in the closing prose), and
   a photo gallery reusing .cgs-gallery wholesale.
   ========================================================================== */

/* --- Intro: text + one photo. Same grid mechanics as .cgs-fleet-intro but
   its own rule set — page-scoped classes, not shared, per this file's own
   per-page-prefix convention. */
.cgs-lift-intro__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: clamp(28px, 4vw, 56px);
}
.cgs-lift-intro__text { display: flex; flex-direction: column; justify-content: center; }
.cgs-lift-intro__inner h2 {
  margin: 0 0 18px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cgs-lift-intro__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  min-height: 320px;
}
.cgs-lift-intro__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (max-width: 767.98px) {
  .cgs-lift-intro__inner { grid-template-columns: 1fr; }
  .cgs-lift-intro__media { min-height: 240px; order: -1; }
}

/* --- Statement: full-bleed photo band with the pull-quote text held in its
   own floating card, not washed directly onto the photo — a plain gradient
   scrim still let the crane rigging's diagonal lines cross straight through
   the letterforms behind it. The card gives the text a hard, clean edge
   against the photo instead, while the photo itself stays fully visible
   everywhere the card doesn't cover it. Still a full-bleed photo band, not
   a second grid split — distinct from .cgs-lift-intro's boxed two-column
   layout above it. */
.cgs-lift-statement {
  position: relative;
  overflow: hidden;
  color: #fff;
  display: flex;
  align-items: center;
  min-height: clamp(380px, 44vw, 540px);
  padding: clamp(48px, 6vw, 80px) 0;
}
.cgs-lift-statement__media { position: absolute; inset: 0; z-index: 0; }
.cgs-lift-statement__media img {
  width: 100%;
  height: 100%;
  object-fit: fill;
}
.cgs-lift-statement__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 34, 56, .1) 0%, rgba(8, 34, 56, .45) 100%);
}
.cgs-lift-statement > .container-fluid { position: relative; z-index: 1; width: 100%; }
.cgs-lift-statement__inner {
  max-width: 640px;
  background: rgba(8, 34, 56, .85);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-left: 3px solid var(--cgs-cyan-400);
  border-radius: var(--cgs-radius);
  padding: clamp(28px, 3.4vw, 44px) clamp(28px, 3.4vw, 48px);
  box-shadow: var(--cgs-shadow-lg);
}
.cgs-lift-statement__inner h2 {
  margin: 0 0 16px;
  font-size: 32px;
  font-weight: 800;
  color: #fff;
}
.cgs-lift-statement__inner p {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  font-weight: 500;
  color: rgba(255, 255, 255, .92);
  text-wrap: balance;
}

@media (max-width: 767.98px) {
  .cgs-lift-statement { min-height: 0; padding: 40px 0; }
  .cgs-lift-statement__inner { max-width: 100%; }
}

/* --- Process: a vertical connected rail, not a card grid or a bare list —
   the seven steps read as one plotted sequence, alternating text-only
   rows with text+photo rows for rhythm rather than repeating one row
   shape seven times. */
.cgs-lift-process__head { max-width: 640px; margin: 0 auto clamp(40px, 5vw, 60px); text-align: center; }
.cgs-lift-process__head h2 { margin: 0; font-size: clamp(24px, 2.8vw, 32px); font-weight: 800; }

.cgs-lift-rail { position: relative; max-width: 1080px; margin: 0 auto; }
.cgs-lift-rail::before {
  content: '';
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: 27px;
  width: 2px;
  background: rgba(255, 255, 255, .14);
}
.cgs-lift-step {
  position: relative;
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 22px;
  padding-bottom: clamp(24px, 3vw, 32px);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  margin-bottom: clamp(24px, 3vw, 32px);
}
.cgs-lift-step:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: none; }
.cgs-lift-step__num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(46, 159, 214, .4);
  color: var(--cgs-cyan-300);
  font-family: var(--cgs-font);
  font-size: 15px;
  font-weight: 800;
}
.cgs-lift-step__body {
  padding-top: 8px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 24px;
}
.cgs-lift-step__text { flex: 1 1 340px; min-width: 0; }
.cgs-lift-step h3 { margin: 0 0 8px; font-size: 18px; font-weight: 800; color: #fff; }
.cgs-lift-step p { margin: 0; font-size: 15.5px; line-height: 1.7; color: rgba(255, 255, 255, .72); max-width: 52ch; }
.cgs-lift-step__media {
  flex: 0 0 240px;
  width: 240px;
  aspect-ratio: 4 / 3;
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-lift-step__media img { display: block; width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 767.98px) {
  .cgs-lift-step__media { flex-basis: 100%; width: 100%; max-width: 320px; aspect-ratio: 16 / 10; }
}

@media (max-width: 575.98px) {
  .cgs-lift-rail::before { left: 23px; }
  .cgs-lift-step { grid-template-columns: 48px 1fr; }
  .cgs-lift-step__num { width: 48px; height: 48px; font-size: 13px; }
}

/* --- Capabilities: asymmetric 2+2 bento (photo, photo / photo, text) for
   the four discrete capabilities buried in the client's closing prose
   (docs/CONTENT.md: "That last block is prose, but it lists four discrete
   capabilities... which is how it should be laid out on the page"). */
.cgs-lift-capabilities__head { max-width: 680px; margin: 0 0 clamp(32px, 4vw, 48px); }
.cgs-lift-capabilities__head h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3vw, 36px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cgs-lift-capabilities__head p { margin: 0; color: var(--cgs-slate); font-size: 16.5px; line-height: 1.7; }

.cgs-lift-bento {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(16px, 2vw, 22px);
}
.cgs-lift-bento__cell {
  position: relative;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  min-height: 280px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.cgs-lift-bento__cell--wide { grid-column: span 2; }
.cgs-lift-bento__cell img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
.cgs-lift-bento__cell:hover img,
.cgs-lift-bento__cell:focus-within img { transform: scale(1.045); }
.cgs-lift-bento__cell::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(8, 34, 56, .05) 30%, rgba(8, 34, 56, .88) 100%);
}
.cgs-lift-bento__body { position: relative; z-index: 1; padding: clamp(20px, 2.4vw, 28px); color: #fff; }
.cgs-lift-bento__body h3 { margin: 0 0 8px; font-size: 18px; font-weight: 800; color: #fff; }
.cgs-lift-bento__body p { margin: 0; font-size: 15px; line-height: 1.65; color: rgba(255, 255, 255, .82); }

/* Text-only cell (no photo): white card with a hairline border, not a tint —
   this section is itself .cgs-section--tint, so a var(--cgs-surface) fill
   here was invisible against its own background. Same white+border
   treatment as .cgs-fleet-tile--icon, which sits in the identical
   tinted-section context on our-fleet.php. */
.cgs-lift-bento__cell--text {
  background: #fff;
  border: 1px solid var(--cgs-line);
  box-shadow: var(--cgs-shadow);
  justify-content: center;
  min-height: 220px;
}
.cgs-lift-bento__cell--text::after { display: none; }
.cgs-lift-bento__cell--text .cgs-lift-bento__body {
  color: var(--cgs-ink);
  padding: clamp(28px, 3vw, 40px);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.cgs-lift-bento__cell--text h3 { color: var(--cgs-navy-900); font-size: 24px; }
.cgs-lift-bento__cell--text p { color: var(--cgs-slate); font-size: 16px; max-width: 52ch; }

@media (max-width: 767.98px) {
  .cgs-lift-bento { grid-template-columns: 1fr; }
  .cgs-lift-bento__cell--wide { grid-column: span 1; }
}

/* --- Gallery: static 3-across grid, not a sliding carousel (2026-08-29 —
   the swiper tried here first peeked a sliver of the next photo and made
   the images small; client wants project-freight-forwarding.php's
   original big static grid used everywhere instead). Shared across all
   four service-detail pages. [data-gallery-pager] + cgs.js group photos
   3-per-page via each link's data-gallery-page and show one group at a
   time — .is-hidden just display:none's the rest, so the visible group
   always fills the grid's 3 (or fewer, on a page's last partial group)
   columns at full size. The arrows only render in markup when a page has
   more than 3 photos (see each service page's own PHP), and cgs.js
   disables whichever one is at a boundary. The shared .cgs-gallery-trigger
   lightbox binding from includes/scripts.php binds every photo regardless
   of which group is on screen, so it can still arrow through the full set. */
.cgs-svc-gallery__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin: 0 0 clamp(28px, 3.5vw, 40px);
}
.cgs-svc-gallery__intro { max-width: 62ch; margin: 0; }
.cgs-svc-gallery__intro h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--cgs-navy-900);
  text-wrap: balance;
}
.cgs-svc-gallery__intro p { margin: 0; font-size: 16.5px; line-height: 1.7; color: var(--cgs-slate); }

.cgs-svc-gallery__arrows { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.cgs-svc-gallery__arrow {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex-shrink: 0;
  padding: 0;
  border: 1.5px solid var(--cgs-line);
  border-radius: 50%;
  background: transparent;
  color: var(--cgs-navy-900);
  font-size: 14px;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out),
              border-color 200ms var(--ease-out),
              color 200ms var(--ease-out),
              transform 160ms var(--ease-out);
}
.cgs-svc-gallery__arrow:active { transform: scale(0.94); }
.cgs-svc-gallery__arrow:disabled { opacity: .38; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .cgs-svc-gallery__arrow:not(:disabled):hover {
    background: var(--cgs-navy-900);
    border-color: var(--cgs-navy-900);
    color: #fff;
  }
}

.cgs-svc-gallery__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2vw, 22px);
}
.cgs-svc-gallery__link {
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: var(--cgs-radius);
  overflow: hidden;
  box-shadow: var(--cgs-shadow);
}
.cgs-svc-gallery__link.is-hidden { display: none; }
.cgs-svc-gallery__link img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms var(--ease-out);
}
.cgs-svc-gallery__link:hover img,
.cgs-svc-gallery__link:focus-visible img { transform: scale(1.05); }

@media (max-width: 991.98px) {
  .cgs-svc-gallery__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575.98px) {
  .cgs-svc-gallery__head { flex-direction: column; align-items: flex-start; }
  .cgs-svc-gallery__grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Shared service-detail components — Project Freight Forwarding, Chartering
   of Tug and Barges, Roll On/Off (project-freight-forwarding.php,
   tug-and-barge-chartering.php, roll-on-roll-off.php)
   -----------------------------------------------------------------------------
   All three render client-supplied copy (docs/CONTENT.md, "Service page 1/
   3/4") with no dedicated per-item photography of their own, unlike Heavy
   Lift's "Breakbulk pics" email set above — so unlike .cgs-lift-*, one
   shared "cgs-svc-*" set covers all three: they are genuinely the same
   shape, not scoped apart for its own sake.
   ========================================================================== */

/* --- Intro: text + one real photo, same split mechanics as .cgs-lift-intro. */
.cgs-svc-intro__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: clamp(28px, 4vw, 56px);
}
.cgs-svc-intro__text { display: flex; flex-direction: column; justify-content: center; }
.cgs-svc-intro__inner h2 {
  margin: 0 0 18px;
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cgs-svc-intro__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--cgs-radius);
  min-height: 320px;
}
.cgs-svc-intro__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (max-width: 767.98px) {
  .cgs-svc-intro__inner { grid-template-columns: 1fr; }
  .cgs-svc-intro__media { min-height: 240px; order: -1; }
}

/* --- Grid: icon-topped card grid for short, independent items (transport
   modes, evaluation criteria, cargo types). auto-fit reflow rather than a
   fixed column count — item counts vary per page (5 / 4 / 4), none a
   multiple of the same number, so a forced 3-up would strand an odd card
   on its own row every time. */
.cgs-svc-grid__head { max-width: 680px; margin: 0 0 clamp(32px, 4vw, 48px); }
.cgs-svc-grid__head h2 {
  margin: 0 0 12px;
  font-size: clamp(26px, 3vw, 36px);
  font-weight: 800;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.cgs-svc-grid__head p { margin: 0; color: var(--cgs-slate); font-size: 16.5px; line-height: 1.7; }

.cgs-svc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: clamp(18px, 2.2vw, 26px);
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Grid items stretch to equal row height by default, but block-level cells
   don't fill that stretched height on their own — making each <li> a flex
   container lets its one .cgs-svc-grid__cell child fill it, so cards with
   shorter copy (e.g. "Steel plates, wire rope reels.") end up the same
   height as their longer siblings instead of visibly shorter. */
.cgs-svc-grid > li { display: flex; }
.cgs-svc-grid__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 auto;
  background: #fff;
  border: 1px solid var(--cgs-line);
  border-radius: var(--cgs-radius);
  box-shadow: var(--cgs-shadow);
  padding: clamp(26px, 3vw, 34px) clamp(22px, 2.6vw, 28px);
  text-align: center;
  text-decoration: none;
  transition: border-color 200ms var(--ease-out), box-shadow 200ms var(--ease-out);
}
a.cgs-svc-grid__cell:hover,
a.cgs-svc-grid__cell:focus-visible { text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  a.cgs-svc-grid__cell:hover { border-color: var(--cgs-cyan-400); box-shadow: var(--cgs-shadow-lg); }
}
.cgs-svc-grid__icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin: 0 auto 16px;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  color: var(--cgs-cyan-300);
  font-size: 18px;
}
.cgs-svc-grid__cell h3 { margin: 0 0 8px; font-size: 16px; font-weight: 700; color: var(--cgs-navy-900); }
.cgs-svc-grid__cell p { margin: 0; font-size: 15px; line-height: 1.65; color: var(--cgs-slate); }
.cgs-svc-grid__link-note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--cgs-blue-500);
}

/* --- Rail: numbered vertical connected sequence for genuinely ordered (or,
   as of 2026-08-26, simply grouped-for-consistency) steps. Same mechanics
   as .cgs-lift-rail, including an optional photo slot per step — none of
   the three pages had step-level photography at launch, but the admin's
   service_sections editor can attach one later (the `image` column
   already exists), so the layout needs to hold up the moment one arrives
   rather than requiring a template change too. */
.cgs-svc-process__head { max-width: 640px; margin: 0 auto clamp(40px, 5vw, 60px); text-align: center; }
.cgs-svc-process__head h2 { margin: 0; font-size: clamp(24px, 2.8vw, 32px); font-weight: 800; }
.cgs-svc-process__head p {
  margin: 16px 0 0;
  font-size: 16.5px;
  line-height: 1.7;
  color: rgba(255, 255, 255, .78);
  text-wrap: balance;
}

.cgs-svc-rail { position: relative; max-width: 900px; margin: 0 auto; }
.cgs-svc-rail::before {
  content: '';
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: 27px;
  width: 2px;
  background: rgba(255, 255, 255, .14);
}
.cgs-svc-step {
  position: relative;
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 22px;
  padding-bottom: clamp(24px, 3vw, 32px);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  margin-bottom: clamp(24px, 3vw, 32px);
}
.cgs-svc-step:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: none; }
.cgs-svc-step__num {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--cgs-navy-900);
  border: 1px solid rgba(46, 159, 214, .4);
  color: var(--cgs-cyan-300);
  font-family: var(--cgs-font);
  font-size: 15px;
  font-weight: 800;
}
.cgs-svc-step__body {
  padding-top: 8px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 24px;
}
.cgs-svc-step__text { flex: 1 1 340px; min-width: 0; }
.cgs-svc-step h3 { margin: 0 0 8px; font-size: 18px; font-weight: 800; color: #fff; }
.cgs-svc-step p { margin: 0; font-size: 15.5px; line-height: 1.7; color: rgba(255, 255, 255, .72); max-width: 60ch; }
.cgs-svc-step__media {
  flex: 0 0 240px;
  width: 240px;
  aspect-ratio: 4 / 3;
  border-radius: var(--cgs-radius);
  overflow: hidden;
}
.cgs-svc-step__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 767.98px) {
  .cgs-svc-step__media { flex-basis: 100%; width: 100%; max-width: 320px; aspect-ratio: 16 / 10; }
}
@media (max-width: 575.98px) {
  .cgs-svc-rail::before { left: 23px; }
  .cgs-svc-step { grid-template-columns: 48px 1fr; }
  .cgs-svc-step__num { width: 48px; height: 48px; font-size: 13px; }
}

