/* ==========================================================================
   UVEC
   Design system modeled on the GSEC v2 layout language, re-skinned entirely
   in the UVEC brand palette extracted from uvec.ae:
     primary accent  #5ce1e6 (cyan)
     secondary       #003366 (deep navy)
     dark            #050a18 (near-black navy)
     slate surfaces  #0f172a -> #1e293b (gradient)
     muted text      #64748b · light neutrals #f8fafc / #f1f5f9 / #e2e8f0
   Typeface: Poppins (self-hosted, SIL OFL), matching uvec.ae.
   ========================================================================== */

/* ---- Fonts ---------------------------------------------------------------- */
/* ---- Faces: the exact set gsec-v2 ships -----------------------------------
   Poppins 300/400/500 only - gsec has no heavier weight, and the type system
   below never asks for one. Split latin / latin-ext the way gsec subsets them.
   Libre Baskerville Regular (400 500), Bold (600 700) and Italic, so the
   serif headings and the italic <em> in the tagline both have a real face
   instead of a synthesised one. */
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 300; font-display: swap;
  src: url('../fonts/poppins/poppins-300-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 300; font-display: swap;
  src: url('../fonts/poppins/poppins-300-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/poppins/poppins-400-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/poppins/poppins-400-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('../fonts/poppins/poppins-500-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap;
  src: url('../fonts/poppins/poppins-500-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Libre Baskerville'; font-style: normal; font-weight: 400 500; font-display: swap;
  src: url('../fonts/libre-baskerville/LibreBaskerville-Regular.woff2') format('woff2'); }
@font-face { font-family: 'Libre Baskerville'; font-style: normal; font-weight: 600 700; font-display: swap;
  src: url('../fonts/libre-baskerville/LibreBaskerville-Bold.woff2') format('woff2'); }
@font-face { font-family: 'Libre Baskerville'; font-style: italic; font-weight: 400 500; font-display: swap;
  src: url('../fonts/libre-baskerville/LibreBaskerville-Italic.woff2') format('woff2'); }

/* ---- Tokens --------------------------------------------------------------- */
:root {
  --dark:   #050a18;   /* reserved for text on cyan / deep accents (uvec.ae --dark) */
  --navy:   #003366;   /* secondary (uvec.ae --secondary) */
  --brand:  #0d2a5a;   /* logo navy: footer, dark accents */
  --cyan:   #5ce1e6;   /* THE accent (uvec.ae --primary) */
  /* The same accent a shade deeper, which is what lets it hold as *type*
     on a light ground: #5ce1e6 dissolves into paper, this does not. Used
     for the accent word in section headings and for the phase names. */
  --accent-lt: #2bbecd;
  /* The same accent again, one step deeper, for accent text set at body size.
     #2bbecd is sized for display type; at 1rem over a photograph it thins out
     to the point of not being readable, and this is what holds there. */
  --accent-lt-ink: #1fa4b5;
  --slate:  #0f172a;   /* card surface on dark (uvec.ae --uvec-dark) */
  --slate2: #1e293b;   /* gradient partner */
  --paper:  #f8fafc;   /* light section background (uvec.ae pill bg) */
  --line:   #e2e8f0;   /* light borders (uvec.ae pill border) */
  --muted:  #64748b;   /* muted body text (uvec.ae --uvec-muted) */
  --ink:    #0f172a;   /* headings on light */
  --body:   #334155;   /* body text on light */
  --white:  #ffffff;

  --white-70: rgba(255,255,255,0.72);
  --white-40: rgba(255,255,255,0.42);
  --white-12: rgba(255,255,255,0.12);
  --dark-12:  rgba(5,10,24,0.12);
  --cyan-14:  rgba(92,225,230,0.14);

  --sans: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --serif: 'Libre Baskerville', Georgia, 'Times New Roman', serif;

  --header-h: 84px;
  --header-solid-h: 66px;

  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-move: cubic-bezier(0.45, 0, 0.55, 1);
  --dur-fast: 0.2s;
  --dur-med:  0.6s;
  --dur-slow: 1s;

  --pad-x: clamp(20px, 5vw, 90px);
  --maxw: 1560px;
}

/* ---- Reset / base --------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--sans);
  font-weight: 400;
  color: var(--body);
  background: var(--white);
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: none; background: none; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
p { margin: 0; }
::selection { background: var(--cyan); color: var(--dark); }
:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; border-radius: 2px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* ---- Typography ----------------------------------------------------------- */
.display {
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.01em;
  font-size: clamp(2.6rem, 7vw, 6.4rem);
  font-family: var(--serif);}
/* 4rem is gsec's number for this tier, but gsec's headings are two or three
   short words. Several of these carry an authored <br> and run to 33 characters
   a segment, which at 64px in a half-width column broke into one-word lines.
   3.4rem is the largest that keeps every heading on the site to two words a
   line or more - still well above the 2.7rem it was before. */
.h2 {
  font-weight: 500;
  line-height: 1.06;
  letter-spacing: -0.01em;
  font-size: clamp(1.9rem, 4.6vw, 3.4rem);
  font-family: var(--serif);}
.h3 {
  font-weight: 500;
  line-height: 1.1;
  font-size: clamp(1.5rem, 2.6vw, 2.3rem);
  font-family: var(--serif);}
.lead { font-size: clamp(1.05rem, 1.5vw, 1.35rem); line-height: 1.55; font-weight: 300; }
.eyebrow {
  display: inline-block;
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: 16px;
}
.eyebrow--dark { color: var(--navy); }
.accent { color: var(--cyan); font-style: normal; }

/* The line that sits under a section title. The eyebrow is now the title, so
   the statement that used to be the heading reads as a deck beneath it: one
   step down in size, Poppins 300 like every other piece of running copy, and
   wide enough to hold two words a line. */
.sectionsub {
  margin-top: 14px;
  font-weight: 300;
  font-size: clamp(1.1rem, 1.8vw, 1.55rem);
  line-height: 1.35;
  color: var(--body);
  max-width: 30ch;
}
.sectionsub .accent { color: var(--accent-lt); font-style: normal; }

/* The page says "Our Key Sectors" once, as a small label above the first group
   name, instead of repeating it as a heading over every group: said once it
   labels the whole list, said five times it was noise above the name that
   actually distinguishes each block. */
.sectionlabel {
  font-size: 0.74rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 14px;
}

/* ---- Layout --------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding-inline: var(--pad-x); }
.section { padding-block: clamp(64px, 9vw, 130px); position: relative; }
.section--paper { background: var(--paper); }
.section--navy { background: linear-gradient(150deg, var(--brand) 0%, var(--navy) 100%); color: var(--white); }
/* The heading sits in the first column and the body copy in the second. An even
   split gave the heading ~600px, which at this size broke several of them into
   one-word lines; 1.35fr buys it about 85px more, which is what the longest of
   them needed, and still leaves the paragraph a comfortable measure. */
.two-col { display: grid; grid-template-columns: 1.35fr 1fr; gap: clamp(32px, 6vw, 96px); align-items: start; }
@media (max-width: 860px) { .two-col { grid-template-columns: 1fr; } }

/* ---- Buttons -------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 14px 26px;
  background: var(--cyan);
  color: var(--dark);
  font-size: 0.92rem;
  font-weight: 400;
  border-radius: 3px;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
              transform 0.14s var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.btn svg { width: 16px; height: 16px; flex: 0 0 16px; transition: transform var(--dur-fast) var(--ease-out); }
.btn svg path { stroke: currentColor; }
.btn:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--brand); color: var(--white); box-shadow: 0 8px 28px rgba(13,42,90,0.25); }
  .btn:hover svg { transform: translateX(4px); }
}
/* outline variant for light surfaces */
.btn--ghost { background: transparent; color: var(--ink); border: 1px solid var(--dark-12); box-shadow: none; }
.btn--ghost svg path { stroke: var(--navy); }
@media (hover: hover) and (pointer: fine) {
  .btn--ghost:hover { background: var(--brand); color: var(--white); box-shadow: none; border-color: var(--brand); }
}
/* outline variant for dark surfaces */
.btn--line { background: transparent; color: var(--white); border: 1px solid var(--white-40); }
.btn--line svg path { stroke: var(--cyan); }
@media (hover: hover) and (pointer: fine) {
  .btn--line:hover { background: var(--white); color: var(--dark); }
}

/* ==========================================================================
   Header
   ========================================================================== */
.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 900;
  height: var(--header-h);
  background: transparent;
  color: var(--white);
  transition: background var(--dur-fast) var(--ease-out), height var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
/* soft navy gradient so the white logo and links read over any hero photo */
.header::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 170px;
  background: linear-gradient(to bottom, rgba(9,28,60,0.6) 0%, rgba(9,28,60,0.3) 45%, rgba(9,28,60,0) 100%);
  transition: opacity var(--dur-fast) var(--ease-out);
  pointer-events: none;
  z-index: -1;
}
.header.is-solid,
html.mnav-open .header {
  background: var(--white);
  color: var(--ink);
  box-shadow: 0 6px 24px rgba(13,42,90,0.08);
}
.header.is-solid { height: var(--header-solid-h); }
.header.is-solid::before, html.mnav-open .header::before { opacity: 0; }
/* logo swap: light wordmark over photo, full-color on white */
.brand .brand__dark { display: none; }
.header.is-solid .brand__light, html.mnav-open .brand__light { display: none; }
.header.is-solid .brand__dark, html.mnav-open .brand__dark { display: block; }
.header__inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding-inline: var(--pad-x);
  max-width: var(--maxw);
  margin: 0 auto;
}
.header__accent-line {
  position: absolute;
  left: 0; bottom: -1px;
  height: 2px; width: 100%;
  background: var(--cyan);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
}
.header.is-solid .header__accent-line { opacity: 1; }

.brand { display: flex; align-items: center; }
.brand img { height: 30px; width: auto; display: block; }
@media (max-width: 640px) { .brand img { height: 26px; } }

.nav { display: flex; align-items: center; gap: 34px; }
.nav__link {
  position: relative;
  font-size: 0.92rem;
  font-weight: 400;
  color: inherit;
  padding-block: 4px;
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: var(--cyan);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-fast) var(--ease-out);
}
/* gsec marks the page you are on by switching that one link into the serif and
   letting it run a size larger, not by bolding it - there is no bold to reach
   for. .is-active is here too because the two pages under the About Us dropdown
   mark the parent with a class rather than aria-current. */
.nav__link[aria-current="page"],
.nav__link.is-active {
  font-family: var(--serif);
  font-size: 1.05rem;
}
.nav__link:hover::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); }
.header.is-solid .nav__link[aria-current="page"], html.mnav-open .nav__link[aria-current="page"] { color: var(--navy); }

.header__right { display: flex; align-items: center; }
.header__right .btn { padding: 11px 20px; font-size: 0.78rem; }
@media (max-width: 1320px) { .nav { gap: 20px; } .nav__link { font-size: 0.84rem; letter-spacing: 0.07em; } }

/* ---- Mobile nav ---- */
.mnav-toggle { display: none; }
.mnav { display: none; }
@media (max-width: 1099px) {
  .nav, .header__right { display: none; }
  .mnav-toggle {
    display: inline-flex;
    align-items: center; justify-content: center;
    width: 46px; height: 46px;
    margin-right: -10px;
    color: inherit;
    -webkit-tap-highlight-color: transparent;
    z-index: 2;
  }
  .mnav-toggle__box { position: relative; width: 26px; height: 14px; }
  .mnav-toggle__bar {
    position: absolute; left: 0;
    width: 100%; height: 2px;
    background: currentColor; border-radius: 2px;
    transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
  }
  .mnav-toggle__bar:nth-child(1) { top: 0; }
  .mnav-toggle__bar:nth-child(2) { top: 6px; }
  .mnav-toggle__bar:nth-child(3) { top: 12px; }
  .mnav-toggle.is-open .mnav-toggle__bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  .mnav-toggle.is-open .mnav-toggle__bar:nth-child(2) { opacity: 0; }
  .mnav-toggle.is-open .mnav-toggle__bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

  .mnav {
    display: flex;
    position: fixed;
    inset: 0;
    z-index: 899;
    flex-direction: column;
    padding: calc(var(--header-h) + 20px) var(--pad-x) max(28px, env(safe-area-inset-bottom));
    background: var(--white);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s var(--ease-out), visibility 0.3s;
  }
  .mnav.is-open { opacity: 1; visibility: visible; }
  html.mnav-open { overflow: hidden; }

  .mnav__list { display: flex; flex-direction: column; gap: clamp(2px, 1vh, 10px); }
  .mnav__link {
    display: inline-flex;
    align-items: baseline;
    gap: 16px;
    padding: 12px 0;
    font-weight: 500;
    letter-spacing: -0.01em;
    font-size: clamp(1.8rem, 7.5vw, 2.7rem);
    line-height: 1.15;
    color: var(--ink);
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.45s var(--ease-out), transform 0.45s var(--ease-out);
  font-family: var(--serif);}
  .mnav.is-open .mnav__link { opacity: 1; transform: none; }
  .mnav__idx { font-size: 0.8rem; font-weight: 400; color: var(--navy); letter-spacing: 0.04em; }
  .mnav__link[aria-current="page"] { color: var(--navy); }
  .mnav__foot { margin-top: auto; padding-top: clamp(24px, 5vh, 44px); }
  .mnav__contact { margin-top: 20px; color: var(--muted); font-size: 0.92rem; }
  .mnav__contact a { color: var(--ink); border-bottom: 1px solid var(--cyan); padding-bottom: 2px; }
}

/* ---- Scroll progress line ---- */
.progress { position: fixed; left: 0; top: 0; height: 3px; width: 100%; z-index: 901; pointer-events: none; }
.progress > span { display: block; height: 100%; width: 100%; background: var(--cyan); transform: scaleX(0); transform-origin: left center; }

/* ==========================================================================
   Motion primitives (IntersectionObserver adds .in-view)
   ========================================================================== */
.reveal-line { overflow: hidden; display: block; padding-bottom: 0.18em; margin-bottom: -0.18em; }
.reveal-line > span { display: block; transform: translateY(110%); transition: transform 0.9s var(--ease-out); }
.in-view .reveal-line > span, .reveal-line.in-view > span { transform: translateY(0); }
.rise { opacity: 0; transform: translateY(26px); transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out); }
.rise.in-view { opacity: 1; transform: none; }
.rise.d1 { transition-delay: 0.08s; } .rise.d2 { transition-delay: 0.16s; }
.rise.d3 { transition-delay: 0.24s; } .rise.d4 { transition-delay: 0.32s; }
html.no-js .reveal-line > span { transform: none; }
html.no-js .rise { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal-line > span { transform: none !important; transition: none !important; }
  .rise { opacity: 1 !important; transform: none !important; transition: none !important; }
}

.img-mask { position: relative; overflow: hidden; border-radius: 4px; }
.img-mask img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  a.card-link:hover .img-mask img, .img-hover:hover img { transform: scale(1.045); }
}

/* ==========================================================================
   HERO (home): full-bleed photo, rotating headline
   ========================================================================== */
.hero {
  position: relative;
  /* Fills the viewport, like gsec's hero. This used to be locked to the video's
     own 16 / 9 so the frame was never cropped, but that only lines up with the
     screen on a 16 / 9 display: on the 16 / 10 and 3 / 2 ratios most laptops
     actually ship, the hero came up 90-160px short and the next section showed
     under it. Filling the screen and letting object-fit crop the sides is the
     right trade - the footage is a backdrop, not the subject. */
  height: 100svh;
  min-height: 560px;
  color: var(--white);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
/* Under ~1000px the 16:9 cap collapses the hero (432px at 768 wide, 211px at 375),
   which is too short for the headline and the two pills. Here the hero keeps its
   height and the footage takes the side crop instead: the lesser of the two. */
@media (max-width: 1000px) {
  /* A hair under full height on a phone, so the band below peeks and the page
     reads as scrollable. */
  .hero { height: 92svh; min-height: 560px; }
}
/* The poster sits on the container as the fallback layer, so a slow connection,
   an unsupported codec, reduced-motion, or JS-off all still show a real hero
   rather than the flat navy. The video paints over it once it can play. */
.hero__media {
  position: absolute; inset: 0; z-index: 0;
  background: var(--dark) url('../images/hero-video-poster.jpg?v=4') center/cover no-repeat;
}
.hero__media img,
.hero__video {
  width: 100%; height: 100%;
  object-fit: cover;          /* fills the hero at any ratio: never stretched */
  display: block;
}
/* Reduced motion: no looping footage. The poster underneath takes over, so the
   hero still reads as intended instead of going blank. */
@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none; }
}
/* No overlay: the footage is meant to read clear, so legibility lives on the
   text itself (see the .hero__title text-shadow) rather than in a wash
   over the video. Kept as an element so a scrim can be reinstated in one line. */
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  /* gsec's scrim, in UVEC's navy: a wash down from the top so the header reads,
     and a heavier one up from the bottom so the headline and the buttons sit on
     something solid. Doing the work here rather than in a text-shadow is what
     lets the type stay crisp - a shadow heavy enough to carry white text over
     bright video is a shadow you can see as blur. */
  background:
    linear-gradient(to bottom, rgba(9,28,60,0.55) 0%, rgba(9,28,60,0) 22%),
    linear-gradient(to top, rgba(9,28,60,0.75) 0%, rgba(9,28,60,0.15) 45%, rgba(9,28,60,0.25) 100%);
}
.hero__inner {
  position: relative; z-index: 2;
  max-width: var(--maxw); margin: 0 auto;
  width: 100%;
  padding: calc(var(--header-h) + 20px) var(--pad-x) clamp(56px, 9vh, 110px);
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.hero__title {
  max-width: 32ch;
  /* All the legibility the hero has, now that the scrim is gone. Layered from a
     near-outline outwards: the two tight stops give the letterforms a hard edge
     against busy detail, the wide stops lift them off bright frames. Shadows do
     not count toward a WCAG contrast ratio, so this improves how readable the
     line looks without changing what it measures: see the note in the handover. */
  /* One soft layer, not four. The scrim above now carries the contrast, so this
     only has to keep the letterforms off busy detail - stacked shadows at this
     size read as blur on the glyph edges. */
  text-shadow: 0 2px 18px rgba(9,28,60,0.45);
  /* Libre Baskerville, like every other heading on the site. gsec holds its own
     hero below the display maximum so the headline does not shout over the
     frame; this goes one step further again, because the size is what decides
     whether the first line stays a single line. "Engineering a better tomorrow"
     needs about 15.6x the font size to set unbroken; at 5.2rem that came to
     1298px against 1296px of available measure and broke by two pixels. The
     5.2vw term keeps it on one line from roughly 480px up, and below that it
     wraps, which is the right answer on a phone. */
  font-family: var(--serif);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.14;
  font-size: clamp(2.2rem, 5.2vw, 4.8rem);
}
.hero__btns { display: flex; gap: 14px; margin-top: 36px; flex-wrap: wrap; }

/* pill buttons with circular accent arrow (hero) */
.btn-pill {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 10px 10px 10px 26px;
  /* gsec's .btn + .btn--light exactly: a hairline rim at 40% white over a
     transparent fill, and no text-shadow at all. The shadow and the dark fill
     that used to stand in for a scrim were what made these look thick and
     smeared; the scrim does that job now, so the label can be clean. */
  border: 1px solid var(--white-40);
  border-radius: 999px;
  font-size: 0.92rem;
  font-weight: 400;
  color: var(--white);
  background: transparent;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out), transform 0.14s var(--ease-out);
}
.btn-pill__icon {
  width: 34px; height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  background: var(--cyan);
  display: grid;
  place-items: center;
  transition: transform var(--dur-fast) var(--ease-out);
}
.btn-pill__icon svg { width: 14px; height: 14px; display: block; transition: transform var(--dur-fast) var(--ease-out); }
.btn-pill__icon svg path { stroke: var(--dark); }
.btn-pill:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .btn-pill:hover { background: var(--white); color: var(--dark); border-color: var(--white); }
  .btn-pill:hover .btn-pill__icon { transform: scale(1.1); }
  .btn-pill:hover .btn-pill__icon svg { transform: translateX(2px); }
}

@media (max-width: 640px) {
  /* No hero-title size override any more: the display scale's own clamp
     handles small screens, and the home hero is set at exactly the size every
     other hero on the site is. */
  .hero__btns { row-gap: 12px; }
}

/* ==========================================================================
   Page hero (inner pages)
   ========================================================================== */
.page-hero {
  position: relative;
  height: 100svh;
  min-height: 560px;
  color: var(--white);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
}
.page-hero__bg { position: absolute; inset: 0; }
.page-hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* A portrait photograph in a landscape hero: centred, the crop lands on empty
   array. Held low, on the crew. */
.page-hero__bg--low img { object-position: 50% 100%; }
.page-hero__bg::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(9,28,60,0.45) 0%, rgba(9,28,60,0.12) 50%, rgba(9,28,60,0) 75%),
    linear-gradient(to top, rgba(9,28,60,0.88), rgba(9,28,60,0.3) 55%, rgba(9,28,60,0.08) 100%);
}
.page-hero__inner {
  position: relative; z-index: 2;
  max-width: var(--maxw); margin: 0 auto;
  padding: calc(var(--header-h) + 20px) var(--pad-x) clamp(40px, 6vw, 76px);
  width: 100%;
}
.page-hero__title { font-size: clamp(2.6rem, 7vw, 6.4rem); }
.page-hero__intro { color: rgba(255,255,255,0.92); font-weight: 300; max-width: 62ch; margin-top: 18px; font-size: clamp(1.05rem, 1.5vw, 1.35rem); text-shadow: 0 1px 14px rgba(9,28,60,0.45); }
@media (max-width: 640px) { .page-hero { min-height: 520px; } }


/* ==========================================================================
   Stats band
   ========================================================================== */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(24px, 4vw, 60px); }
.stat { border-top: 2px solid var(--cyan); padding-top: 20px; }
.stat__num {
  font-weight: 400;
  font-size: clamp(2.9rem, 5.5vw, 4.8rem);
  line-height: 1;
  color: var(--brand);
  font-family: var(--serif);}
.section--navy .stat__num { color: var(--white); }
.stat__label { margin-top: 10px; font-size: 0.8rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase; color: var(--navy); }
.section--navy .stat__label { color: var(--cyan); }
.stat__sub { margin-top: 6px; font-size: 0.9rem; font-weight: 300; color: var(--muted); }
.section--navy .stat__sub { color: var(--white-70); }
@media (max-width: 860px) { .stats { grid-template-columns: repeat(2, 1fr); } }

/* ---- Stats over a parallax photo band ----------------------------------- */
.statband { position: relative; overflow: hidden; }
.statband__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
/* Taller than the band and hung above it, so the whole travel range is covered
   at both ends of the scroll. main.js drives the transform; if it never runs the
   image still fills the band exactly, so this fails safe rather than gapping. */
.statband__bg img {
  position: absolute;
  left: 0; top: -28%;
  width: 100%; height: 128%;
  object-fit: cover;
  transform: translate3d(0, 0, 0);
  will-change: transform;
}
/* Tuned against measured contrast rather than by eye: at these alphas the white
   figures still read at ~10:1 and the cyan labels ~6.5:1, which leaves the array
   visible instead of scrimming it down to a flat navy. */
.statband__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(150deg, rgba(13,42,90,0.68) 0%, rgba(0,51,102,0.62) 100%);
}
.statband > .wrap { position: relative; z-index: 2; }
.statband .stat { border-top-color: var(--cyan); }
.statband .stat__num { color: var(--white); }
.statband .stat__label { color: var(--cyan); }
.statband .stat__sub { color: var(--white-70); }

/* No parallax without motion, and centre the frame since nothing will move it. */
@media (prefers-reduced-motion: reduce) {
  .statband__bg img { top: -14%; transform: none !important; }
}
html.no-js .statband__bg img { top: -14%; }
@media (max-width: 420px) { .stats { grid-template-columns: 1fr 1fr; gap: 24px; } }

/* ==========================================================================
   ISO chips
   ========================================================================== */
.iso-row { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.iso-chip {
  display: inline-flex; align-items: center;
  padding: 8px 0;
  border-bottom: 2px solid var(--cyan);
  font-size: 0.88rem; font-weight: 400; letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--navy);
}
.section--navy .iso-chip { color: var(--white); }

/* ==========================================================================
   Horizontal card slider (sectors on home)
   ========================================================================== */
.hslider { position: relative; padding-block: clamp(64px, 9vw, 130px); overflow: hidden; }
.hslider__head { margin-bottom: clamp(28px, 4vw, 50px); display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 20px; }
.hslider__stage { position: relative; }
.hslider__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 52px; height: 52px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.55);
  background: rgba(5,10,24,0.35);
  color: #fff;
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.hslider__arrow--prev { left: var(--pad-x); }
.hslider__arrow--next { right: var(--pad-x); }
.hslider__arrow svg { width: 20px; height: 20px; }
.hslider__arrow svg path { stroke: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .hslider__arrow:hover:not(:disabled) { background: var(--cyan); border-color: var(--cyan); color: var(--dark); }
}
.hslider__arrow:active:not(:disabled) { transform: translateY(-50%) scale(0.94); }
.hslider__arrow:disabled { opacity: 0.22; cursor: not-allowed; }
.hslider__viewport {
  overflow: hidden;
  cursor: grab;
  touch-action: pan-y;
  -webkit-user-select: none; user-select: none;
}
.hslider__viewport.is-dragging { cursor: grabbing; }
.hslider__track { display: flex; gap: clamp(16px, 2vw, 26px); padding-inline: var(--pad-x); will-change: transform; }
.hslider__card {
  position: relative;
  flex: 0 0 auto;
  width: min(80vw, 340px);
  aspect-ratio: 4 / 5;
  display: block;
  overflow: hidden;
  border-radius: 4px;
  color: #fff;
  background: var(--dark);
}
.hslider__card-media { position: absolute; inset: 0; overflow: hidden; }
.hslider__card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--dur-med) var(--ease-out); }
.hslider__card-media::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(5,10,24,0.82) 0%, rgba(5,10,24,0.2) 36%, rgba(5,10,24,0) 58%);
}
.hslider__card-scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(5,10,24,0.94) 0%, rgba(5,10,24,0.55) 46%, rgba(5,10,24,0) 82%);
  opacity: 0;
  transition: opacity 0.35s var(--ease-out);
}
.hslider__card-cap { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; padding: clamp(20px, 2vw, 30px); }
.hslider__card-num { font-size: 0.92rem; font-weight: 400; letter-spacing: -0.01em; color: var(--cyan); display: block; margin-bottom: 8px; font-family: var(--serif);}
.hslider__card-title {
  font-weight: 500; color: #fff; letter-spacing: -0.01em;
  line-height: 1.2; font-size: clamp(1.35rem, 2vw, 1.8rem);
  text-shadow: 0 1px 12px rgba(5,10,24,0.5);
  transition: transform 0.35s var(--ease-out);
  font-family: var(--serif);}
.hslider__card-reveal { max-height: 0; overflow: hidden; transition: max-height 0.35s var(--ease-out); }
.hslider__card-text {
  margin-top: 10px;
  color: rgba(255,255,255,0.85); font-weight: 300; font-size: 0.92rem; line-height: 1.55;
  opacity: 0; transform: translateY(12px);
  transition: opacity 0.35s var(--ease-out), transform 0.35s var(--ease-out);
}
.hslider__card-more {
  margin-top: 12px;
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--cyan); font-size: 0.78rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  opacity: 0; transform: translateY(12px);
  transition: opacity 0.35s var(--ease-out), transform 0.35s var(--ease-out);
}
.hslider__card-more svg { width: 15px; height: 15px; }
.hslider__card-more svg path { stroke: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .hslider__card:hover .hslider__card-media img,
  .hslider__card:focus-within .hslider__card-media img { transform: scale(1.05); }
  .hslider__card:hover .hslider__card-scrim,
  .hslider__card:focus-within .hslider__card-scrim { opacity: 1; }
  .hslider__card:hover .hslider__card-reveal,
  .hslider__card:focus-within .hslider__card-reveal { max-height: 16em; }
  .hslider__card:hover .hslider__card-text,
  .hslider__card:focus-within .hslider__card-text,
  .hslider__card:hover .hslider__card-more,
  .hslider__card:focus-within .hslider__card-more { opacity: 1; transform: none; }
}
@media (hover: none) {
  .hslider__card-scrim { opacity: 1; }
  .hslider__card-reveal { max-height: 16em; }
  .hslider__card-text, .hslider__card-more { opacity: 1; transform: none; }
}
.hslider__foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
  margin-top: clamp(26px, 3.5vw, 44px);
}
.hslider__progress { position: relative; flex: 0 0 auto; width: clamp(120px, 22vw, 260px); height: 2px; background: var(--dark-12); overflow: hidden; }
.section--navy .hslider__progress { background: var(--white-12); }
.hslider__progress-thumb { position: absolute; left: 0; top: 0; height: 100%; width: 40px; background: var(--cyan); will-change: transform, width; }
@media (min-width: 700px)  { .hslider__card { width: 44vw; } }
@media (min-width: 1100px) { .hslider__card { width: clamp(320px, 29vw, 420px); } }
@media (max-width: 700px) {
  .hslider__arrow { width: 46px; height: 46px; }
  .hslider__arrow--prev { left: 8px; }
  .hslider__arrow--next { right: 8px; }
}

/* ==========================================================================
   Project cycle: one photograph, heading and phases both on it

   The deck sets the phases in a column beside a photograph. Here they run
   along one line, left to right, which is the shape the content already has:
   one project, six phases, in order. Heading and phases share a single frame
   rather than sitting on two different grounds.

   Each phase is a control: choosing one cross-fades the photograph behind the
   whole section to the project work that phase actually looks like. That is
   what sets the weight of the scrim - heavy enough that six different
   photographs all carry the same type, light enough that the change registers.
   ========================================================================== */
.cycle { position: relative; overflow: hidden; background: var(--paper); isolation: isolate;
  border-block: 1px solid var(--line); }
/* The frame is what motion.js drifts; the two layers inside it are what
   main.js cross-fades. Keeping the transform on the frame means the drift
   never has to be re-applied to a layer that was swapped mid-scroll. */
.cycle__stage { position: absolute; inset: 0; z-index: 0; }
.cycle__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
  opacity: 0; transition: opacity 0.7s var(--ease-out);
}
.cycle__img.is-active { opacity: 1; }
/* White, not black: the section above this one is a photograph under a dark
   overlay, and a second dark photographic band directly beneath it read as one
   long strip with no edge between the two. Same picture, opposite weight. */
.cycle__scrim {
  position: absolute; inset: 0; z-index: 1;
  /* Deliberately thin, and no blur: a blurred plate reads as an out-of-focus
     photograph rather than a clear one behind type. The type carries its own
     contrast instead - the phase colours below are set dark enough to hold
     against the picture at this weight. */
  background: linear-gradient(to bottom,
              rgba(255,255,255,0.46) 0%, rgba(255,255,255,0.40) 45%, rgba(255,255,255,0.56) 100%);
}
.cycle__content { position: relative; z-index: 2; padding-block: clamp(56px, 7vw, 104px); }
.cycle__title {
  color: var(--ink); font-weight: 500;
  line-height: 1.1; letter-spacing: -0.01em;
  font-size: clamp(1.9rem, 4.6vw, 3.4rem);
  max-width: 26ch;
  margin-bottom: clamp(44px, 5.5vw, 84px);
  font-family: var(--serif);}
.cycle__title em { font-style: normal; color: #106470; }

/* Each phase carries its own rule rather than one line running behind all six:
   a continuous rule would have to be punched through by every numeral, and on
   a photograph there is no flat colour to punch it with. */
.cycle__rail {
  list-style: none; margin: 0; padding-inline: 0;
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  column-gap: clamp(10px, 1.4vw, 24px);
}
.cstep {
  position: relative;
  padding-top: clamp(16px, 1.8vw, 24px);
  border-top: 1px solid rgba(15,23,42,0.22);
}
/* The selected marker rides over the rule rather than thickening it, so
   choosing a phase never nudges the six columns by a pixel. */
.cstep::before {
  content: ''; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  background: var(--accent-lt);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 0.5s var(--ease-out);
}
.cstep.is-active::before, .cstep:hover::before { transform: scaleX(1); }
/* While the rail is rotating, the chosen phase's rule is the clock: it fills
   across one interval, and main.js advances on the fill finishing rather than
   on a timer of its own. One source of truth, so the bar can never disagree
   with the photograph - pausing the fill pauses the advance with it. */
.cycle__rail.is-running .cstep.is-active::before {
  animation: cstep-fill var(--cstep-dur, 5000ms) linear forwards;
}
.cycle__rail.is-running.is-paused .cstep.is-active::before { animation-play-state: paused; }
@keyframes cstep-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* The whole phase is the control: a button reset that keeps the column
   layout the <li> used to carry. */
.cstep__btn {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: clamp(12px, 1.4vw, 18px);
  width: 100%; margin: 0; padding: 0;
  background: none; border: 0; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
  opacity: 0.94; transition: opacity var(--dur-fast) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.cstep.is-active .cstep__btn, .cstep__btn:hover, .cstep__btn:focus-visible { opacity: 1; }
.cstep__btn:focus-visible { outline: 2px solid var(--navy); outline-offset: 6px; }
.cstep__num {
  font-weight: 400; line-height: 1;
  font-size: clamp(2rem, 3.1vw, 3rem);
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  font-family: var(--serif);}
.cstep__name {
  color: #0a464f; font-weight: 500;
  line-height: 1.4; font-size: clamp(0.92rem, 1.1vw, 1.15rem);
  font-family: var(--serif);}

/* A cross-fade is motion; without it the swap is instant, which is the right
   answer for anyone who asked not to be moved. */
@media (prefers-reduced-motion: reduce) {
  .cycle__img { transition: none; }
  .cstep::before { transition: none; }
  /* No rotation for anyone who asked not to be moved, so the rule is simply
     the selected marker again rather than a bar that fills. */
  .cycle__rail.is-running .cstep.is-active::before { animation: none; transform: scaleX(1); }
}

@media (max-width: 1000px) {
  /* Standing the rail up makes the section tall, and a 2:1 photograph cropped
     into a narrow tall frame is mostly sky - which the desktop scrim erases to
     flat white. Lighter here, so the photograph still registers. */
  .cycle__scrim {
    background: linear-gradient(to bottom,
                rgba(255,255,255,0.42) 0%, rgba(255,255,255,0.48) 40%, rgba(255,255,255,0.60) 100%);
  }
  /* Six columns of type on a tablet is six columns of one word per line: the
     rail stands up and runs down the page instead. */
  .cycle__rail { grid-template-columns: 1fr; }
  .cstep { padding-block: clamp(14px, 2.4vw, 20px); }
  .cstep__btn {
    flex-direction: row; align-items: baseline; gap: clamp(14px, 3vw, 26px);
  }
  .cstep__num { font-size: 2.2rem; min-width: 2.2ch; }
  .cstep__name { font-size: 1.15rem; }
}

/* ==========================================================================
   Stat wall: slide 4 of the company profile

   Ten rectangles over four columns of photograph. The five fills are the
   slide's own, resolved out of ppt/theme/theme1.xml through the lumMod and
   lumOff each shape carries:

     l3 #83CBEB   accent1  lum 40/60      l2 #46B1E1   accent1  lum 60/40
     l1 #4E95D9   tx2      lum 50/50      d2 #215F9A   tx2      lum 75/25
     d1 #163E64   tx2      lum 90/10

   The deck sets white on all ten. White on the three light fills is between
   1.7:1 and 3.1:1, so the caption under each number would be unreadable on
   half the wall; those three take the deck's own navy instead, which is the
   smallest change that keeps every tile legible and every fill exact.
   ========================================================================== */
/* The photograph runs the whole section, heading included, rather than
   starting at the tiles: two backgrounds stacked one on the other made the
   heading look like a different section. A white veil, solid at the top and
   gone by the time it reaches the rectangles, is what keeps the heading and
   the paragraph readable over it. */
.statwall { position: relative; overflow: hidden; background: var(--paper); border-block: 1px solid var(--line); }
.statwall__wall {
  position: absolute; inset: 0; z-index: 0;
  display: grid; grid-template-columns: repeat(4, 1fr);
}
/* The four strips are already cut to the part of each frame that carries the
   subject, so the band can take them straight down the middle. */
.statwall__wall img { width: 100%; height: 100%; object-fit: cover; display: block; }
.statwall__content { position: relative; z-index: 2; padding-block-end: clamp(56px, 7vw, 96px); }
/* The veil is the heading block's own background, not a share of the section's
   height: sized that way it is solid behind every line of type and gone by the
   exact point the rectangles start, at any screen width and any text length. */
.statwall__headwrap {
  /* The fade is stated from the bottom in pixels, not as a share of the block,
     so it occupies exactly this padding and no more: every line of type sits
     on solid paper whatever the screen does to the paragraph's height, and the
     gradient still lands on nothing but the gap above the rectangles. */
  --veil-fade: clamp(72px, 9vw, 130px);
  padding-block: clamp(56px, 7vw, 96px) var(--veil-fade);
  background: linear-gradient(to bottom,
              rgba(248,250,252,1) 0%,
              rgba(248,250,252,1) calc(100% - var(--veil-fade)),
              rgba(248,250,252,0.74) calc(100% - var(--veil-fade) * 0.6),
              rgba(248,250,252,0.30) calc(100% - var(--veil-fade) * 0.25),
              rgba(248,250,252,0) 100%);
}
/* cqw is measured against this box, which is what lets every number below be
   stated as the fraction of a rectangle that the slide states it as. */
.statwall__inner {
  padding-inline: var(--pad-x); max-width: var(--maxw); margin-inline: auto;
  container-type: inline-size;
}

/* Slide geometry, in EMU, from ppt/slides/slide4.xml:
     rectangle   cx 2225169   cy 1277679        ratio 1.7415 : 1
     columns at  1060918  3284401  5509570  7733053  9958222
                 step 2224326 against a width of 2225169, so the five
                 rectangles in a row abut: no gap, they are one bar
     rows at     3429000 and 4935166, leaving 228487 between them
                 = 17.9% of a rectangle's height
     type        Century Gothic, 20pt bold over 14pt regular, centred both ways
                 20pt = 254000 EMU = 11.42% of a rectangle's width
                 14pt = 177800 EMU =  7.99% of a rectangle's width
   A rectangle is one fifth of this container, so one tile width = 20cqw and
   every figure above follows from it. */
.statgrid {
  list-style: none; margin: 0;
  display: grid; grid-template-columns: repeat(5, 1fr);
  column-gap: 0;
  row-gap: 16px;              /* fallback where cqw is unavailable */
  row-gap: 2.06cqw;           /* 17.9% of a rectangle's height */
}
.swtile {
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  text-align: center;
  aspect-ratio: 2225169 / 1277679;
  padding: 2.05% 4.1%;        /* the slide's own tIns / lIns */
}
.swtile__num {
  font-weight: 400; line-height: 1.18; letter-spacing: 0;
  font-size: 1.8rem;
  font-size: 2.28cqw;
  font-family: var(--serif);}
.swtile__cap {
  font-weight: 400; line-height: 1.2; letter-spacing: 0;
  font-size: 1.05rem;
  font-size: 1.6cqw;
}
.swtile--l3 { background: #83CBEB; color: #0E2841; }
.swtile--l2 { background: #46B1E1; color: #0E2841; }
.swtile--l1 { background: #4E95D9; color: #0E2841; }
.swtile--d2 { background: #215F9A; color: #fff; }
.swtile--d1 { background: #163E64; color: #fff; }

@media (max-width: 900px) {
  /* Two rectangles to a row instead of five: the bar still abuts across, and a
     tile at a fifth of a phone screen would put 'Battery Energy Storage
     System' on five lines. */
  .statgrid { grid-template-columns: repeat(2, 1fr); row-gap: 5.15cqw; }
  .statwall__wall { grid-template-columns: repeat(2, 1fr); }
  .swtile__num { font-size: 6.8cqw; }
  .swtile__cap { font-size: 4cqw; }
}
@media (max-width: 359px) {
  .statgrid { grid-template-columns: 1fr; row-gap: 10.3cqw; }
  .swtile__num { font-size: 13.6cqw; }
  .swtile__cap { font-size: 8cqw; }
}

/* ==========================================================================
   Sector strips: the two 'Our Key Sectors' slides, as they are drawn

   The deck does not give each sector a card. It gives each one a band of
   photograph running the full width of the slide with the name set on it, one
   under the other, and the list reads as a single run of country. These are
   those bands, with those photographs.

   The line under each name is what the deck leaves out: the services that
   sector actually covers. It stays out of the way until the cursor is on the
   band, and stands permanently on anything without a cursor.
   ========================================================================== */
.strips { list-style: none; margin: 0; }
.strip {
  position: relative; overflow: hidden;
  min-height: clamp(104px, 10vw, 158px);
  display: flex; align-items: center;
  border-top: 1px solid var(--line);
}
.strip:last-child { border-bottom: 1px solid var(--line); }
.strip__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 1.1s var(--ease-out);
}
/* Left-weighted, because that is the only side carrying type: the right half
   of every band stays a photograph. */
.strip__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to right,
              rgba(5,10,24,0.82) 0%, rgba(5,10,24,0.62) 34%, rgba(5,10,24,0.22) 68%, rgba(5,10,24,0.06) 100%);
  transition: opacity var(--dur-med) var(--ease-out);
}
.strip__label {
  position: relative; z-index: 2;
  display: flex; align-items: baseline; gap: clamp(14px, 1.8vw, 26px);
  padding-block: clamp(16px, 1.8vw, 24px);
  padding-inline: var(--pad-x);
  max-width: var(--maxw); width: 100%; margin-inline: auto;
}
.strip__num {
  flex: 0 0 auto;
  color: var(--cyan); font-weight: 400;
  font-size: clamp(0.85rem, 1.2vw, 1rem); letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  font-family: var(--serif);}
.strip__body { display: block; min-width: 0; }
.strip__name {
  display: block;
  color: #fff; font-weight: 500;
  letter-spacing: -0.01em; line-height: 1.2;
  font-size: clamp(1.2rem, 2.3vw, 2rem);
  font-family: var(--serif);}
.strip__desc {
  display: block; max-width: 62ch;
  color: rgba(255,255,255,0.88); font-weight: 300; line-height: 1.5;
  font-size: clamp(0.8rem, 0.95vw, 0.95rem);
}

/* Where there is a cursor, the description is the reward for stopping on a
   band: it opens the row rather than being crammed into it, so a strip at rest
   is still the deck's clean run of names. */
@media (hover: hover) {
  .strip__desc {
    max-height: 0; opacity: 0; margin-top: 0;
    overflow: hidden;
    transition: max-height var(--dur-med) var(--ease-out),
                opacity var(--dur-fast) var(--ease-out),
                margin-top var(--dur-med) var(--ease-out);
  }
  .strip:hover .strip__desc,
  .strip:focus-within .strip__desc { max-height: 5em; opacity: 1; margin-top: 10px; }
  .strip:hover .strip__img { transform: scale(1.045); }
  .strip:hover .strip__scrim { opacity: 0.92; }
}
/* No cursor, no hover: the line simply stands. */
@media (hover: none) {
  .strip__desc { margin-top: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .strip__img, .strip__desc { transition: none; }
  .strip:hover .strip__img { transform: none; }
}

/* ==========================================================================
   Client logo bar
   --------------------------------------------------------------------------
   Four logos, so there is nothing to scroll. A marquee here would only be
   the same four names going past again, which reads as padding rather than
   as a longer list: they sit still and share the width instead.
   ========================================================================== */
.clients { background: var(--white); border-block: 1px solid var(--line); padding-block: clamp(14px, 1.6vw, 22px); }
.clients__bar { display: flex; align-items: center; gap: clamp(18px, 2.6vw, 40px); }
.clients__label {
  flex: 0 0 auto;
  font-size: 0.72rem; font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
  border-right: 1px solid var(--line); padding-right: clamp(18px, 2.6vw, 40px);
}
.logobar { flex: 1 1 auto; min-width: 0; }
.logobar__row {
  display: flex; align-items: center;
  justify-content: space-evenly;
  gap: clamp(20px, 4vw, 64px);
  flex-wrap: wrap;
}
.logobar__item { flex: 0 0 auto; display: flex; align-items: center; }
/* Height, never width: the four files have very different aspect ratios, and
   matching their heights is what makes them read as one row. */
.logobar__item img { height: 46px; width: auto; display: block; }
@media (max-width: 720px) {
  .clients__bar { flex-direction: column; align-items: flex-start; gap: 12px; }
  .clients__label { border-right: none; padding-right: 0; }
  .logobar { width: 100%; }
  .logobar__row { justify-content: flex-start; gap: clamp(18px, 6vw, 36px); }
  .logobar__item img { height: 34px; }
}

/* ==========================================================================
   Division bands
   ========================================================================== */
.band {
  position: relative;
  min-height: 48vh;
  display: flex;
  align-items: center;
  color: var(--white);
  overflow: hidden;
  background: var(--dark);
}
.band__bg { position: absolute; inset: 0; }
.band__bg img { width: 100%; height: 100%; object-fit: cover; }
.band__bg::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to right, rgba(10,30,64,0.92) 0%, rgba(10,30,64,0.68) 45%, rgba(10,30,64,0.25) 100%);
}
.band__inner {
  position: relative; z-index: 2;
  max-width: var(--maxw); margin: 0 auto;
  padding: clamp(64px, 9vw, 120px) var(--pad-x);
  width: 100%;
}
.band--right .band__inner { display: flex; justify-content: flex-end; }
.band__content { max-width: 56ch; }
.band__text { color: var(--white-70); font-weight: 300; margin: 20px 0 30px; font-size: 1.05rem; }

/* ==========================================================================
   Project cards
   The photograph used to sit under the caption, with a gradient ramp over the
   whole frame to keep white text legible on it: 0.94 opaque at the bottom and
   still 0.60 at mid-height. Between that and a four-line caption stack, almost
   none of the picture survived, which on a page whose whole job is showing the
   work was the wrong trade. Photo and text are now separated: the image gets its
   own box with nothing over it, the words get a panel beneath. Ink on white also
   ends the reliance on text-shadow to carry contrast over an arbitrary frame.
   ========================================================================== */
.pcards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: clamp(18px, 2.4vw, 30px); }
.pcards--five { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
/* Six references, one per sector. auto-fill lands them 4 + 2 at desktop
   widths, which reads as two cards short of a row rather than as a set: an
   explicit three keeps it a full 3 x 2 block. */
.pcards--six { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1000px) { .pcards--six { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .pcards--six { grid-template-columns: 1fr; } }

.pcard {
  position: relative;
  display: flex;
  flex-direction: column;          /* media, then body: body takes the slack */
  border-radius: 6px;
  overflow: hidden;
  background: var(--white);
  border: 1px solid var(--line);
  color: var(--body);
  /* Deliberately no hover transform: .rise animates transform on this same
     element to bring the card in, and the two would fight over it. The shadow
     and the border carry the lift instead. */
  transition: box-shadow 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
}

/* ---- the photograph, unobstructed ---- */
.pcard__media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--paper);
}
.pcard__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.7s var(--ease-out);
}
/* The card's single accent, and the only thing drawn on the image: the same
   cyan hairline the header uses, wiping in from the left on hover. */
.pcard__media::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--cyan);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-out);
}

/* ---- the words, on their own ground ---- */
.pcard__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: clamp(15px, 1.4vw, 22px);
}
.pcard__meta {
  font-size: 0.64rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  /* Navy, not cyan: cyan measures ~1.5:1 on white and would be unreadable at
     this size. Navy clears AA comfortably and is the same accent the eyebrows
     on light sections already use. */
  color: var(--navy);
  display: block;
  margin-bottom: 9px;
  /* One line. Wrapping gave the grid four different body heights and pushed the
     titles to random depths; the full detail is in the modal. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pcard__title {
  font-size: clamp(1.15rem, 1.6vw, 1.45rem);
  font-weight: 500;
  line-height: 1.28;
  /* No capitalize: the titles are authored with the casing they want, and
     capitalize was rewriting "50 MWp PV Plant in Dialakoro" to "In Dialakoro".
     It mattered less when the type sat on a dark photo; on white it reads. */
  color: var(--ink);
  font-family: var(--serif);}
.pcard__sub {
  margin-top: 8px;
  font-size: 0.85rem;
  font-weight: 300;
  line-height: 1.55;
  color: var(--body);
}

/* ---- clickable card affordance ---- */
.pcard[data-title] { cursor: pointer; }
.pcard__more {
  /* margin-top:auto pins this to the bottom of the panel whatever the title and
     description above it come to, so the row of cards lines up. */
  margin-top: auto;
  padding-top: 16px;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.7rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--navy);
}
.pcard__more svg {
  width: 14px; height: 14px;
  transition: transform 0.35s var(--ease-out);
}
.pcard__more svg path { stroke: currentColor; }

@media (hover: hover) and (pointer: fine) {
  .pcard:hover {
    border-color: transparent;
    box-shadow: 0 20px 44px -20px rgba(5, 10, 24, 0.32),
                0 3px 10px -6px rgba(5, 10, 24, 0.18);
  }
  .pcard:hover .pcard__media img { transform: scale(1.05); }
  .pcard:hover .pcard__media::after { transform: scaleX(1); }
  .pcard:hover .pcard__more svg { transform: translateX(4px); }
}
/* Keyboard parity: the projects cards are focusable buttons, so the same state
   has to be reachable without a pointer. */
.pcard:focus-visible .pcard__media::after { transform: scaleX(1); }

/* project detail modal */
.pmodal {
  position: fixed; inset: 0; z-index: 1200;
  display: grid; place-items: center;
  padding: 20px;
  background: rgba(9,28,60,0.6);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; visibility: hidden;
  transition: opacity 0.3s var(--ease-out), visibility 0.3s;
}
.pmodal.is-open { opacity: 1; visibility: visible; }
.pmodal__dialog {
  position: relative;
  width: min(860px, 94vw);
  max-height: 88vh;
  overflow: auto;
  background: var(--white);
  border-radius: 10px;
  box-shadow: 0 40px 120px rgba(5,10,24,0.5);
  transform: translateY(18px) scale(0.98);
  transition: transform 0.35s var(--ease-out);
}
.pmodal.is-open .pmodal__dialog { transform: none; }
.pmodal__close {
  position: absolute; top: 14px; right: 14px; z-index: 3;
  width: 42px; height: 42px;
  border-radius: 50%;
  background: rgba(5,10,24,0.55);
  color: #fff;
  display: grid; place-items: center;
  transition: background var(--dur-fast) var(--ease-out);
}
.pmodal__close:hover { background: var(--brand); }
.pmodal__close svg { width: 18px; height: 18px; }
.pmodal__close svg path { stroke: currentColor; }
.pmodal__media { aspect-ratio: 16 / 8; background: var(--paper); }
.pmodal__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pmodal__body { padding: clamp(24px, 3.4vw, 44px); }
.pmodal__meta { font-size: 0.74rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase; color: var(--navy); margin-bottom: 10px; }
.pmodal__title { font-weight: 500; letter-spacing: -0.01em; color: var(--ink); font-size: clamp(1.7rem, 3.2vw, 2.5rem); margin-bottom: 14px; font-family: var(--serif);}
.pmodal__desc { color: var(--muted); font-weight: 300; max-width: 64ch; margin-bottom: 22px; }
.pmodal__facts { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 14px; border-top: 1px solid var(--line); padding-top: 20px; }
.pmodal__facts div { min-width: 0; }
.pmodal__facts dt { font-size: 0.68rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); margin-bottom: 4px; }
.pmodal__facts dd { margin: 0; font-weight: 400; color: var(--ink); font-size: 0.95rem; }
@media (max-width: 640px) { .pmodal__facts { grid-template-columns: 1fr; gap: 12px; } }

/* reference table rows */
.refs { border-top: 1px solid var(--dark-12); }
.ref {
  display: grid;
  grid-template-columns: 150px minmax(0, 1.1fr) minmax(0, 1.6fr) 170px 110px;
  gap: clamp(14px, 2.5vw, 40px);
  align-items: baseline;
  padding: clamp(16px, 2vw, 22px) 4px;
  border-bottom: 1px solid var(--dark-12);
  transition: background var(--dur-fast) var(--ease-out);
}
.ref:hover { background: var(--paper); }
.ref__cat { font-size: 0.7rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase; color: var(--navy); }
.ref__title { font-weight: 500; color: var(--ink); font-size: 1rem; font-family: var(--serif);}
.ref__desc { color: var(--muted); font-weight: 300; font-size: 0.92rem; }
.ref__where { color: var(--body); font-size: 0.88rem; }
.ref__status { font-size: 0.7rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase; }
.ref__status--ongoing { color: #8a5a0a; }
.ref__status--completed { color: #0e6b52; }
.ref.is-hidden { display: none; }
@media (max-width: 900px) {
  .ref { grid-template-columns: 1fr 1fr; gap: 6px 18px; }
  .ref__cat { grid-column: 1; }
  .ref__status { grid-column: 2; text-align: right; }
  .ref__title { grid-column: 1 / -1; }
  .ref__desc { grid-column: 1 / -1; }
  .ref__where { grid-column: 1 / -1; }
}

/* filter buttons */
.filters { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: clamp(24px, 3vw, 40px); }
.filter {
  padding: 9px 18px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--white);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  transition: all var(--dur-fast) var(--ease-out);
}
.filter[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: var(--white); }
@media (hover: hover) { .filter:hover { border-color: var(--navy); color: var(--navy); } .filter[aria-pressed="true"]:hover { color: var(--white); } }

/* ==========================================================================
   Editorial alternating sections (sectors page)
   ========================================================================== */
.editorial {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 6vw, 90px);
  align-items: center;
  padding-block: clamp(56px, 8vw, 110px);
  scroll-margin-top: calc(var(--header-solid-h) + 20px);
}
.editorial--reverse .editorial__media { order: 2; }
.editorial--reverse .editorial__text { order: 1; }
.editorial__media { aspect-ratio: 4 / 3.2; border-radius: 4px; }
.editorial__title { margin-bottom: 18px; }
.editorial__prose { color: var(--muted); margin-bottom: 26px; font-weight: 300; font-size: 1.02rem; }
.linklist { border-top: 1px solid var(--dark-12); }
.linklist__row {
  display: flex; align-items: center;
  gap: 20px;
  padding: 13px 4px;
  border-bottom: 1px solid var(--dark-12);
  font-size: 0.98rem;
  font-weight: 400;
  color: var(--ink);
  transition: padding-left var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) { .linklist__row:hover { padding-left: 12px; border-bottom-color: var(--cyan); } }
.editorial__prose:last-child { margin-bottom: 0; }
/* The home page runs two editorial rows under one shared section heading, and
   each ends in a link out to its division page. The rule list above it already
   closes on a hairline, so the button needs its own air, not the list's. */
.editorial__cta { margin-top: clamp(26px, 3vw, 38px); }
@media (max-width: 860px) {
  .editorial { grid-template-columns: 1fr; }
  .editorial--reverse .editorial__media { order: 0; }
  .editorial--reverse .editorial__text { order: 0; }
  .editorial__media { aspect-ratio: 4 / 3; }
}

/* ==========================================================================
   Value / principle cards
   ========================================================================== */
.vgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(18px, 2.6vw, 34px); }
.vcard {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: clamp(24px, 2.6vw, 36px);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) { .vcard:hover { transform: translateY(-4px); box-shadow: 0 18px 44px rgba(5,10,24,0.08); border-color: var(--cyan); } }
.vcard__icon { display: inline-flex; width: 46px; height: 46px; color: var(--navy); margin-bottom: 18px; }
.vcard__icon svg { width: 100%; height: 100%; stroke: currentColor; }
.vcard__title { font-size: 1.3rem; font-weight: 500; color: var(--ink); margin-bottom: 8px; font-family: var(--serif);}
.vcard__text { color: var(--muted); font-weight: 300; font-size: 0.94rem; }
.vgrid--dark .vcard { background: var(--white-12); border-color: transparent; }
.vgrid--dark .vcard__icon { color: var(--cyan); }
.vgrid--dark .vcard__title { color: #fff; }
.vgrid--dark .vcard__text { color: var(--white-70); }
.vgrid--three { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 1000px) { .vgrid, .vgrid--three { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .vgrid, .vgrid--three { grid-template-columns: 1fr; } }

/* ISO cards (about page) */
/* The standard, said plainly: the number and what it governs. The certificate
   documents themselves were four dense scans that nobody reads at card size,
   and the year belongs on the certificate, not on the wall. */
.certs { display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(18px, 2.6vw, 34px); }
.cert {
  border-top: 3px solid var(--cyan);
  background: var(--white);
  border-inline: 1px solid var(--line); border-bottom: 1px solid var(--line);
  border-radius: 0 0 6px 6px;
  padding: clamp(24px, 2.8vw, 38px) clamp(20px, 2.2vw, 30px);
  display: flex; flex-direction: column; gap: 10px;
  transition: transform var(--dur-med) var(--ease-out), box-shadow var(--dur-med) var(--ease-out);
}
@media (hover: hover) {
  .cert:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(13,42,90,0.10); }
}
.cert__code {
  display: block; font-weight: 400; color: var(--ink);
  font-size: clamp(1.6rem, 2.5vw, 2.3rem); line-height: 1.05;
  font-family: var(--serif);}
.cert__name {
  display: block; font-size: 0.72rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--navy); line-height: 1.4;
}
@media (max-width: 1000px) { .certs { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px)  { .certs { grid-template-columns: 1fr; } }

/* ==========================================================================
   Numbered rows (opportunities / impact goals / products)
   ========================================================================== */
.rows { border-top: 1px solid var(--dark-12); }
.rows--light { border-top-color: var(--white-12); }
.row {
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: clamp(18px, 3.5vw, 54px);
  align-items: start;
  padding: clamp(22px, 3vw, 38px) clamp(4px, 1.5vw, 18px);
  border-bottom: 1px solid var(--dark-12);
  transition: background var(--dur-fast) var(--ease-out);
}
.rows--light .row { border-bottom-color: var(--white-12); }
.row:hover { background: var(--paper); }
.rows--light .row:hover { background: rgba(255,255,255,0.05); }
.row__num { font-weight: 400; font-size: clamp(1.9rem, 3.8vw, 3.1rem); color: transparent; -webkit-text-stroke: 1px var(--navy); line-height: 1.1; font-family: var(--serif);}
.rows--light .row__num { -webkit-text-stroke-color: var(--cyan); }
.row__title { font-size: clamp(1.25rem, 2.2vw, 1.75rem); font-weight: 500; color: var(--ink); margin-bottom: 8px; letter-spacing: -0.01em; font-family: var(--serif);}
.rows--light .row__title { color: #fff; }
.row__desc { color: var(--muted); max-width: 70ch; font-weight: 300; }
.rows--light .row__desc { color: var(--white-70); }
@media (max-width: 640px) { .row { grid-template-columns: 52px 1fr; } }

/* ==========================================================================
   Closing CTA: photo wall with floating white card
   ========================================================================== */
.gridwall { position: relative; overflow: hidden; background: var(--paper); }
.gridwall__wall { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; padding: 12px; }
/* Vertical strips, the way the decks band their imagery: five full-height
   columns running edge to edge with no gap and no corner radius. */
.gridwall--strips { min-height: 68vh; display: flex; align-items: center; }
.gridwall--strips .gridwall__wall {
  position: absolute; inset: 0;
  grid-template-columns: repeat(5, 1fr);
  gap: 0; padding: 0;
}
.gridwall--strips .gridwall__wall img {
  height: 100%; border-radius: 0; opacity: 0.38;
}
.gridwall--strips .gridwall__center { position: relative; inset: auto; width: 100%; }
/* The wall is a ghost of the work, not a photograph: held right down so the
   copy can sit straight on it with no card to carry it. */
.gridwall__wall img {
  width: 100%; height: 38vh; object-fit: cover; border-radius: 3px;
  opacity: 0.16;
}
.gridwall__center {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  /* No halo behind the copy: the wall is held light enough to carry the type
     on its own, and a scrim under a headline this size reads as a smudge. */
}
.gridwall__box {
  padding: clamp(20px, 3vw, 40px);
  /* 640px left 560px of measure, and "Let's Build Together" needs about 540px at
     this size - close enough that the accent word dropped to its own line. */
  max-width: 820px;
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 20px;
}
.gridwall__title { font-weight: 500; color: var(--ink); font-size: clamp(1.9rem, 4.6vw, 3.4rem); line-height: 1.1; font-family: var(--serif);}
.gridwall__title .accent { color: var(--accent-lt); }
.gridwall__text { color: var(--body); font-weight: 300; max-width: 46ch; }
@media (max-width: 860px) {
  .gridwall__wall { grid-template-columns: repeat(2, 1fr); gap: 10px; padding: 10px; }
  .gridwall__wall img { height: 24vh; }
  /* Three strips at phone width: five would be slivers. */
  .gridwall--strips { min-height: 78vh; }
  .gridwall--strips .gridwall__wall { grid-template-columns: repeat(3, 1fr); }
  .gridwall--strips .gridwall__wall img { height: 100%; }
  .gridwall--strips .gridwall__wall img:nth-child(n+4) { display: none; }
}

/* ==========================================================================
   CTA section
   ========================================================================== */
.cta { position: relative; background: linear-gradient(135deg, rgba(92,225,230,0.18) 0%, rgba(92,225,230,0.06) 100%); border-block: 1px solid var(--line); color: var(--brand); overflow: hidden; }
.cta__inner { position: relative; z-index: 2; padding-block: clamp(64px, 8.5vw, 130px); text-align: center; display: flex; flex-direction: column; align-items: center; gap: 22px; }
.cta__title { font-weight: 500; font-size: clamp(1.9rem, 4.6vw, 3.4rem); line-height: 1.1; max-width: 22ch; color: var(--brand); font-family: var(--serif);}
.cta__text { color: var(--muted); font-weight: 300; max-width: 54ch; font-size: 1.02rem; }
.cta .btn { background: var(--brand); color: var(--white); }

/* Academy closing band: the page ends on the moment it is about — a crew
   standing on a finished plant — rather than on centred text over a tint.
   Photograph on one side, the ask on the other, both full height. */
.handover { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); background: var(--slate); }
.handover__media { position: relative; min-height: clamp(320px, 42vw, 620px); overflow: hidden; }
.handover__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.handover__panel { display: flex; align-items: center; padding: clamp(40px, 5.5vw, 96px) clamp(24px, 4.5vw, 84px); }
.handover__inner { max-width: 46ch; }
.handover__eyebrow {
  color: var(--cyan);
  font-size: 0.68rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase;
  margin-bottom: 16px;
}
.handover__title {
  color: #fff; font-weight: 500; line-height: 1.07;
  font-size: clamp(1.9rem, 4.6vw, 3.4rem);
  font-family: var(--serif);}
.handover__title em { font-style: normal; color: var(--cyan); }
.handover__text { margin-top: 20px; color: var(--white-70); font-weight: 300; font-size: 1rem; line-height: 1.7; }
.handover__panel .btn { margin-top: 30px; }
@media (max-width: 900px) {
  .handover { grid-template-columns: 1fr; }
  .handover__media { min-height: 46vh; }
  .handover__panel { padding-inline: var(--pad-x); }
}
@media (hover: hover) and (pointer: fine) { .cta .btn:hover { background: var(--dark); box-shadow: 0 10px 30px rgba(13,42,90,0.3); } }

/* ==========================================================================
   Contact page
   ========================================================================== */
.contact__grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(40px, 7vw, 100px);
  align-items: start;
}
.contact__heading { margin-bottom: clamp(16px, 2vw, 24px); }
.contact__note { color: var(--muted); font-weight: 300; font-size: 1.05rem; max-width: 44ch; margin-bottom: clamp(28px, 4vw, 44px); }
/* The details are a block of their own, not a continuation of the paragraph
   above them: without a top margin on the first one, "EMAIL" sat on the last
   line of the intro. */
.contact__detail { margin-bottom: clamp(18px, 2.4vw, 28px); }
.contact__detail:first-of-type { margin-top: clamp(26px, 3vw, 38px); }
.contact__detail-label { color: var(--muted); font-size: 0.74rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase; margin-bottom: 5px; }
.contact__detail-val { font-size: 1.18rem; color: var(--ink); font-weight: 400; }
.contact__detail-val a { color: var(--ink); border-bottom: 2px solid var(--cyan); padding-bottom: 2px; transition: color var(--dur-fast) var(--ease-out); }
.contact__detail-val a:hover { color: var(--navy); }
.contact__social { display: flex; gap: 10px; margin-top: 8px; }
.contact__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  color: #fff;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.contact__social svg { width: 19px; height: 19px; fill: currentColor; }

/* Official brand colors, one consistent circle size */
.social--li { background: #0a66c2; }
.social--ig { background: radial-gradient(circle at 30% 110%, #fdf497 0%, #fd5949 45%, #d6249f 60%, #285aeb 90%); }
.social--fb { background: #1877f2; }
@media (hover: hover) {
  .contact__social a:hover, .footer__social a:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(5,10,24,0.35); }
}

.form { display: flex; flex-direction: column; gap: clamp(16px, 2vw, 22px); }
.field { display: flex; flex-direction: column; gap: 7px; }
.field label { font-size: 0.74rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.field input, .field select, .field textarea {
  font-family: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 13px 15px;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.field textarea { resize: vertical; min-height: 130px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--cyan);
  box-shadow: 0 0 0 3px var(--cyan-14);
}
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2vw, 22px); }
@media (max-width: 640px) { .form__row { grid-template-columns: 1fr; } }
.form__success { color: #157f66; font-size: 1rem; margin-top: 14px; opacity: 0; transition: opacity var(--dur-med) var(--ease-out); }
.form__success.is-shown { opacity: 1; }
/* Offices: the address said once, in a block that looks like something.
   The old navy strip under this list repeated the headquarters address that
   was already three lines above it, which is what made it read as filler. */
.offices { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: clamp(14px, 1.8vw, 22px); }
.office {
  position: relative;
  background: linear-gradient(150deg, var(--brand) 0%, var(--navy) 100%);
  color: #fff; border-radius: 6px;
  padding: clamp(24px, 2.6vw, 38px);
  display: flex; flex-direction: column;
  border-top: 3px solid var(--cyan);
}
.office__label {
  font-size: 0.66rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--cyan);
}
.office__city {
  margin-top: 12px;
  font-weight: 500; line-height: 1.05;
  font-size: clamp(1.8rem, 3.1vw, 2.8rem);
  font-family: var(--serif);}
.office__addr { margin-top: 12px; color: var(--white-70); font-weight: 300; font-size: 0.9rem; line-height: 1.6; }
.office__link {
  margin-top: auto; padding-top: 20px;
  display: inline-flex; align-items: center; gap: 8px; align-self: flex-start;
  font-size: 0.76rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--cyan);
}
.office__link svg { width: 15px; height: 15px; stroke: currentColor; transition: transform var(--dur-fast) var(--ease-out); }
@media (hover: hover) { .office__link:hover svg { transform: translateX(4px); } }
/* The reach card is a number, not a place: it gets the inverse treatment so
   the three real offices stay the subject of the row. */
.office--reach { background: var(--white); color: var(--ink); border: 1px solid var(--line); border-top: 3px solid var(--cyan); }
.office--reach .office__label { color: var(--navy); }
.office--reach .office__addr { color: var(--muted); }
@media (max-width: 1000px) { .offices { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px)  { .offices { grid-template-columns: 1fr; } }

@media (max-width: 860px) { .contact__grid { grid-template-columns: 1fr; } }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer { background: var(--paper); color: var(--body); border-top: 2px solid var(--cyan); }
.footer__inner { max-width: var(--maxw); margin: 0 auto; padding: clamp(60px, 7vw, 100px) var(--pad-x) 36px; }
.footer__cols {
  display: grid;
  grid-template-columns: 1.8fr repeat(3, minmax(0, 1fr));
  column-gap: clamp(28px, 3.5vw, 56px);
  row-gap: 40px;
  align-items: start;
}
.footer__intro { max-width: 380px; }
.footer__brand { display: inline-flex; }
.footer__brand img { height: 36px; width: auto; display: block; }
.footer__quote { margin-top: 18px; font-weight: 500; font-size: 1.15rem; color: var(--brand); letter-spacing: -0.01em; line-height: 1.35; font-family: var(--serif);}
.footer__tagline { margin-top: 12px; color: var(--muted); font-weight: 300; font-size: 0.9rem; line-height: 1.6; }
.footer__email { display: inline-block; margin-top: 16px; color: var(--ink); font-weight: 400; border-bottom: 1px solid var(--cyan); padding-bottom: 2px; }
.footer__cta { margin-top: 22px; }
/* Out of the brand column and onto its own row above the legal line, hard right,
   the way the reference footer sets its social icons. */
.footer__social {
  display: flex; gap: 10px;
  justify-content: flex-end;
  margin-top: clamp(28px, 4vw, 48px);
}
.footer__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  color: var(--brand);
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.footer__social svg { width: 18px; height: 18px; fill: currentColor; }
/* Social marks, both rows: outlined rather than filled.
   .social--* paints an official brand circle - LinkedIn blue - which was the
   only saturated shape in an otherwise quiet footer, and since the glyph there
   was already the logo navy it came out navy sitting on blue. Drawing the circle
   instead of filling it keeps the mark legible as a control while the colour
   stays the site's own. The hairline is the navy at low alpha rather than
   --line, so the ring belongs to the glyph it encloses.
   The box size is untouched: border-box, and it is the tap target. */
.contact__social a,
.footer__social a { border: 1px solid rgba(13, 42, 90, 0.22); }
.contact__social a.social--li,
.contact__social a.social--ig,
.contact__social a.social--fb,
.footer__social a.social--li,
.footer__social a.social--ig,
.footer__social a.social--fb { background: none; color: var(--brand); }
@media (hover: hover) {
  /* A drop shadow under a circle that is no longer painted reads as a smudge,
     so the hover is carried by the glyph and its ring instead. */
  .contact__social a:hover,
  .footer__social a:hover {
    box-shadow: none;
    color: var(--accent-lt-ink);
    border-color: var(--accent-lt);
  }
}
.footer__col h4 { font-size: 0.78rem; font-weight: 400; color: var(--navy); margin: 0 0 18px; font-family: var(--serif);}
.footer__col a { display: block; color: var(--body); padding: 5px 0; font-size: 0.92rem; transition: color var(--dur-fast) var(--ease-out); }
.footer__col a:hover { color: var(--navy); }
.footer__legal {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  border-top: 1px solid var(--line);
  /* Carries the separation the certified strip used to provide, so the footer
     keeps its original proportions now that the strip is gone. */
  padding-top: 22px; margin-top: 18px;
  color: var(--muted); font-size: 0.82rem; font-weight: 300;
}
@media (max-width: 1024px) {
  .footer__cols { grid-template-columns: repeat(2, 1fr); }
  .footer__intro { grid-column: 1 / -1; max-width: 52ch; }
}
@media (max-width: 560px) { .footer__cols { grid-template-columns: 1fr; } }

/* ==========================================================================
   Division cards (home): one section, two cards side by side
   ========================================================================== */
.dcards { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 2.6vw, 34px); }
.dcard {
  display: flex; flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  color: var(--ink);
  transition: transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
@media (hover: hover) {
  .dcard:hover { transform: translateY(-4px); border-color: var(--cyan); box-shadow: 0 24px 60px rgba(13,42,90,0.12); }
  .dcard:hover .dcard__media img { transform: scale(1.045); }
}
.dcard__media { aspect-ratio: 16 / 8; overflow: hidden; }
.dcard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.7s var(--ease-out); }
.dcard__body { padding: clamp(24px, 2.8vw, 40px); display: flex; flex-direction: column; flex: 1 1 auto; }
.dcard__title { font-weight: 500; letter-spacing: -0.01em; font-size: clamp(1.6rem, 2.6vw, 2.3rem); font-family: var(--serif);}
.dcard__title { color: var(--ink); }
.dcard__title .accent { color: var(--navy); }
.dcard__text { color: var(--muted); font-weight: 300; margin: 14px 0 22px; font-size: 0.98rem; }
.dcard__link {
  margin-top: auto;
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--navy); font-size: 0.82rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  border-bottom: 2px solid var(--cyan);
  padding-bottom: 6px;
  align-self: flex-start;
}
.dcard__link svg { width: 16px; height: 16px; transition: transform var(--dur-fast) var(--ease-out); }
.dcard__link svg path { stroke: currentColor; }
@media (hover: hover) { .dcard:hover .dcard__link svg { transform: translateX(4px); } }
@media (max-width: 860px) { .dcards { grid-template-columns: 1fr; } }

/* ==========================================================================
   Vision / Mission: editorial rows with photography
   ========================================================================== */
.vmx__row {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(30px, 6vw, 100px);
  align-items: center;
  padding-block: clamp(40px, 5.5vw, 72px);
}
.vmx__row + .vmx__row { border-top: 1px solid var(--line); }
.vmx__row--reverse .vmx__media { order: 2; }
.vmx__media { aspect-ratio: 16 / 11; border-radius: 6px; overflow: hidden; }
.vmx__media img { width: 100%; height: 100%; object-fit: cover; }
/* Reads as a heading rather than an eyebrow: no leading rule, and large enough
   to hold its own above the statement. Tracking eases off as the size goes up ,
   0.2em at this scale would look stretched rather than deliberate. */
.vmx__label {
  font-size: clamp(1.1rem, 1.8vw, 1.45rem);
  font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--navy);
  margin-bottom: 18px;
}
.vmx__statement {
  font-family: var(--serif);
  font-size: clamp(1.25rem, 2vw, 1.8rem);
  line-height: 1.55;
  color: var(--ink);
  letter-spacing: -0.005em;
}
@media (max-width: 860px) {
  .vmx__row { grid-template-columns: 1fr; gap: 22px; }
  .vmx__row--reverse .vmx__media { order: 0; }
}

/* ==========================================================================
   Divisions page
   ========================================================================== */
/* product cards, 2-up */
/* ---- product cards (UVEC Digital): visual, low-text, one CTA each ---- */
.dprod-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 2.6vw, 32px); }
.dprod {
  display: flex; flex-direction: column;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
@media (hover: hover) {
  .dprod:hover { transform: translateY(-5px); border-color: var(--cyan); box-shadow: 0 28px 64px rgba(13,42,90,0.13); }
}
.dprod__head {
  position: relative;
  padding: clamp(28px, 3.2vw, 42px);
  background: linear-gradient(150deg, rgba(92,225,230,0.16) 0%, rgba(13,42,90,0.05) 100%);
  border-bottom: 1px solid var(--line);
  min-height: 116px;
  display: flex; flex-direction: column; justify-content: center;
}
.dprod__name { font-weight: 500; letter-spacing: -0.01em; color: var(--ink); font-size: clamp(1.35rem, 2.1vw, 1.85rem); line-height: 1.15; font-family: var(--serif);}
.dprod__body { padding: clamp(26px, 3vw, 38px); display: flex; flex-direction: column; flex: 1 1 auto; }
.dprod__text { color: var(--muted); font-weight: 300; font-size: 1rem; line-height: 1.7; }
.dprod__foot {
  margin-top: auto;
  padding-top: clamp(24px, 2.8vw, 34px);
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; justify-content: space-between;
}
.dprod__tagline { color: var(--navy); font-weight: 300; font-size: 0.9rem; flex: 1 1 190px; min-width: 0; }

/* The action link out of each product card, and now the only thing in
   .dprod__foot - which keeps its margin-top:auto, so the link still pins to the
   bottom of the card and the three cards stay level whatever their copy runs to.
   Same idiom as .dcard__link, which is the same job on the home page: uppercase,
   navy, cyan rule, arrow that steps forward when the card is hovered. Not a
   .btn: a filled pill inside a card this light would outweigh the copy, and it
   would compete with the card's own hover lift. */
.dprod__link {
  position: relative;
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--navy); font-size: 0.78rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  border-bottom: 2px solid var(--cyan);
  padding-bottom: 6px;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out);
}
/* The link itself is 29px of type and rule. This grows the tappable area past
   44px without moving a pixel of it: it expands into .dprod__foot's own
   padding-top, which is empty space and holds nothing interactive. */
.dprod__link::before { content: ""; position: absolute; top: -10px; right: -8px; bottom: -10px; left: -8px; }
.dprod__link svg { width: 15px; height: 15px; transition: transform var(--dur-fast) var(--ease-out); }
.dprod__link svg path { stroke: currentColor; }
@media (hover: hover) {
  .dprod:hover .dprod__link svg,
  .dprod__link:hover svg { transform: translateX(4px); }
  .dprod__link:hover { color: var(--brand); }
}

@media (max-width: 900px) { .dprod-grid { grid-template-columns: 1fr; } }

/* academy program panels */
.programs { display: grid; gap: clamp(14px, 1.8vw, 22px); }
.program {
  display: grid;
  grid-template-columns: 90px 1fr auto;
  gap: clamp(18px, 3vw, 44px);
  align-items: center;
  background: var(--white);
  border: 1px solid var(--line);
  border-left: 4px solid var(--cyan);
  border-radius: 6px;
  padding: clamp(22px, 2.6vw, 34px);
  transition: box-shadow var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
@media (hover: hover) { .program:hover { transform: translateY(-2px); box-shadow: 0 16px 40px rgba(13,42,90,0.1); } }
.program__num { font-weight: 400; font-size: clamp(2.4rem, 4.3vw, 3.6rem); line-height: 1; color: transparent; -webkit-text-stroke: 1px var(--navy); font-family: var(--serif);}
.program__title { font-weight: 500; letter-spacing: -0.01em; color: var(--ink); font-size: clamp(1.25rem, 2vw, 1.7rem); margin-bottom: 8px; font-family: var(--serif);}
.program__text { color: var(--muted); font-weight: 300; font-size: 0.95rem; max-width: 72ch; }
.program__status {
  align-self: start;
  font-size: 0.7rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--navy);
  white-space: nowrap;
}
@media (max-width: 700px) {
  .program { grid-template-columns: 1fr; gap: 10px; }
  .program__num { font-size: 2.2rem; }
}

/* impact goal cards */
.goals { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(18px, 2.4vw, 30px); }
.goal {
  background: var(--white);
  border: 1px solid var(--line);
  border-top: 3px solid var(--cyan);
  border-radius: 0 0 6px 6px;
  padding: clamp(22px, 2.6vw, 34px);
}
.goal__value { font-weight: 400; font-size: clamp(2.3rem, 4.1vw, 3.4rem); line-height: 1.1; color: var(--ink); font-family: var(--serif);}
.goal__value span { color: var(--navy); }
.goal__text { margin-top: 10px; color: var(--muted); font-weight: 300; font-size: 0.94rem; }
@media (max-width: 1000px) { .goals { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px)  { .goals { grid-template-columns: 1fr; } }

/* ---- utility ---- */
.mt-lg { margin-top: clamp(34px, 5vw, 56px); }
.mt-md { margin-top: clamp(22px, 3vw, 36px); }
.center { text-align: center; }
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 2000;
  background: var(--cyan); color: var(--dark); font-weight: 400;
  padding: 12px 20px; border-radius: 0 0 6px 0;
}
.skip-link:focus { left: 0; }

/* ==========================================================================
   PHOTO-STACK INTRO: home-page entry animation
   Replaces the old logo/progress-line preloader on the home page. Nine
   project photographs drop one by one onto a pile in the centre of a paper
   ground, the wordmark fades in beneath them, and then the top photograph ,
   which IS the hero video's poster frame: scales up onto the hero's own
   rectangle and cross-fades into the footage. One continuous camera move
   from the pile into the film, never a cut.

   Contract
     · Home page only, and only on the first load of a session. The overlay is
       display:none until intro.js opts in, so no JS, an internal referral, or
       a thrown error all leave the page untouched (fails closed, no flash).
     · Only transform and opacity animate. Card geometry is expressed in
       fractions of --pile-w so the whole choreography scales down intact on
       narrow screens rather than being re-timed.
     · The zoom lands on the measured rect of .hero__video. The card carries
       the poster at the same object-fit: cover, in a box set to the hero's own
       aspect ratio by intro.js, so the crop is pixel-identical at the landing
       and the cross-fade has nothing to reveal.
     · prefers-reduced-motion drops the pile entirely and fades the blank
       ground to the hero.
   ========================================================================== */
.intro {
  /* Fails closed: hidden until the head script decides this is a fresh entry. */
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9995;
  /* The site's paper white lifted behind the pile and settling into the
     hairline grey at the edges: the same ground the light sections use, so
     the intro reads as part of the site rather than a splash screen. */
  background: radial-gradient(80% 60% at 50% 40%,
              var(--paper) 0%, var(--paper) 22%, var(--line) 100%);
  /* Last-resort CSS failsafe: if JS never runs its finish(), the overlay still
     leaves the screen. The JS path always beats this by several seconds. */
  animation: intro-failsafe 0s linear 7s forwards;
}
html.intro-full .intro { display: block; }
.intro[hidden] { display: none !important; }
@keyframes intro-failsafe { to { opacity: 0; visibility: hidden; pointer-events: none; } }

html.intro-lock, html.intro-lock body { overflow: hidden; }

/* ---- the stage ---------------------------------------------------------- */
/* Both --pile-w and --mark-gap live here rather than on .intro__pile, because
   .intro__mark is the pile's SIBLING, not its child: a custom property set on
   the pile inherits to the cards but never reaches the lockup, which would then
   silently fall back to the var() default and ignore everything JS measured. */
.intro__stage {
  position: absolute;
  inset: 0;
  --pile-w: clamp(232px, 40vw, 560px);
}

/* A zero-height rule across the viewport: every card centres on it, so the
   pile has one shared anchor point and intro.js only has to reason about the
   offset between that anchor and the hero's centre. 42% rather than 50% to
   leave the wordmark room beneath without crowding the lower edge. */
.intro__pile {
  position: absolute;
  left: 0; right: 0; top: 42%;
  height: 0;
}

/* ---- a photograph on the pile ------------------------------------------
   --sw  width as a fraction of the pile
   --ar  intrinsic aspect ratio (w/h) of the photo
   --ox/--oy  resting offset, as a fraction of the pile width
   --r   resting rotation
   --d   landing delay
   Margins do the centring so the transform is left free for the zoom, and
   transform-origin therefore sits exactly on the pile anchor: the landing
   translate JS writes is simply (hero centre − anchor). */
.intro__card {
  --cw: calc(var(--pile-w) * var(--sw));
  --ch: calc(var(--cw) / var(--ar));
  position: absolute;
  left: 50%;
  top: 0;
  width: var(--cw);
  height: var(--ch);
  margin-left: calc(var(--cw) / -2);
  margin-top: calc(var(--ch) / -2);
  transform: translate(calc(var(--pile-w) * var(--ox)), calc(var(--pile-w) * var(--oy)));
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

/* The rotation and the landing settle live on the inner frame so the outer
   card's transform stays a pure translate/scale for the zoom to overwrite.
   The frame also owns the card's opacity, and therefore has to be the parent
   of the shadow as well as the photo: a shadow outside it would be on screen
   from the first paint, and ten stacked shadows would give the whole pile away
   before a single photograph had landed. */
.intro__frame {
  position: absolute;
  inset: 0;
  transform: rotate(var(--r)) scale(1.16);
  transform-origin: 50% 50%;
  opacity: 0;
  will-change: transform, opacity;
}
/* Separate from the frame so the clip does not cut the shadow off, and so the
   corner radius can be dropped on the hero card alone. */
.intro__crop {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  overflow: hidden;
}
.intro__crop img {
  width: 100%; height: 100%;
  object-fit: cover;            /* same fit as .hero__video: same crop */
  display: block;
}
/* Its own layer rather than a shadow on the crop: it can then be faded with
   opacity alone at the start of the zoom, instead of animating a paint
   property while the card is scaling up. */
.intro__shadow {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  box-shadow: 0 20px 44px -14px rgba(5, 10, 24, 0.30),
              0 4px 12px -5px rgba(5, 10, 24, 0.18);
}

/* The last card is the hero's own frame: square corners and no aspect of its
   own: intro.js sets --ar from the measured hero rect so a single uniform
   scale maps this card exactly onto it. */
.intro__card--hero .intro__crop,
.intro__card--hero .intro__shadow { border-radius: 0; }

/* ---- the landing ------------------------------------------------------- */
/* Each photo arrives slightly large and settles: the drop, not a fade-in.
   The stagger is animation-delay rather than JS timers, so the rhythm is the
   browser's and cannot be jittered by main-thread work. */
@keyframes intro-drop {
  0%   { opacity: 0; transform: rotate(var(--r)) scale(1.16); }
  /* Opaque a quarter of the way in: any slower and two or three cards are
     translucent at once and the pile reads as a haze rather than a stack. */
  26%  { opacity: 1; }
  100% { opacity: 1; transform: rotate(var(--r)) scale(1); }
}
/* --intro-slow is 1 unless ?intro=slow is in the URL, in which case intro.js
   sets it and every duration below stretches with the JS score: so the review
   speed is the same choreography, not a different one. */
html { --intro-slow: 1; }
html.intro-run .intro__frame {
  animation: intro-drop calc(0.44s * var(--intro-slow))
             cubic-bezier(0.16, 0.86, 0.2, 1) var(--d) both;
}
/* The hero card lands heavier than the rest: it is the frame the push is about
   to enter, and its settle is what carries the pile into the hold rather than
   leaving it motionless there. Kept in step with DROP_HERO in intro.js. */
html.intro-run .intro__card--hero .intro__frame {
  animation-duration: calc(0.62s * var(--intro-slow));
}

/* ---- the wordmark ------------------------------------------------------ */
.intro__mark {
  position: absolute;
  left: 0; right: 0;
  /* Never rotated. The cards carry a --r each; the lockup deliberately does
     not, so it reads as the one level thing on screen. Its animations move it
     on Y only. The diagonal inside the mark is the logo artwork's own
     cyan-to-navy break, present in every version of the file on disk. */
  /* intro.js replaces --mark-gap with a measured value that centres the lockup
     in the light below the pile. This is only the pre-script fallback. */
  top: calc(42% + var(--mark-gap, calc(var(--pile-w) * 0.62)));
  text-align: center;
  opacity: 0;
  transform: translateY(14px);
  will-change: transform, opacity;
}
html.intro-run .intro__mark {
  animation: intro-mark calc(0.62s * var(--intro-slow)) cubic-bezier(0.16, 1, 0.3, 1)
             calc(0.3s * var(--intro-slow)) both;
}
@keyframes intro-mark { to { opacity: 1; transform: translateY(0); } }

/* The logo artwork rather than type: the mark carries a diagonal cyan-to-navy
   break across the V that no font can reproduce, so setting UVEC in Poppins was
   never going to be the logo: only a lookalike.
   50px, not the header's 30px: at nav size the mark reads as chrome rather than
   as the thing the intro is presenting. --mark-h is the one number to change if
   you want it nav-sized (30px) or larger. */
.intro__logo {
  --mark-h: 50px;
  display: block;
  height: var(--mark-h);
  width: auto;
  margin: 0 auto;
}
/* ---- the zoom ---------------------------------------------------------- */
/* Everything but the hero card leaves as the push begins, so the frame the
   camera is moving into is the only thing left on screen. */
html.intro-zoom .intro__card:not(.intro__card--hero) {
  opacity: 0;
  transition: opacity calc(0.24s * var(--intro-slow)) cubic-bezier(0.4, 0, 1, 1);
}
html.intro-zoom .intro__shadow { opacity: 0; transition: opacity calc(0.26s * var(--intro-slow)) linear; }
/* A replacement animation, not a transition: intro-mark is still filling
   forwards on this element, and an animation always beats a transition on the
   same property: the wordmark would sit on top of the growing photograph for
   the whole push. Declaring a new animation here retires the old one. */
html.intro-zoom .intro__mark {
  animation: intro-mark-out calc(0.24s * var(--intro-slow)) cubic-bezier(0.4, 0, 1, 1) both;
}
@keyframes intro-mark-out {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(10px); }
}

/* The exit: by the time this runs the card has covered the hero's rect and the
   footage underneath is playing the same frame, so one fade of the whole
   overlay carries both the hero and the rest of the page in together. */
.intro.is-leaving { opacity: 0; transition: opacity calc(0.3s * var(--intro-slow)) cubic-bezier(0.4, 0, 0.6, 1); }

/* ---- Reduced motion: no pile, no push: the ground fades to the hero ----- */
@media (prefers-reduced-motion: reduce) {
  .intro__stage { display: none; }
  .intro { animation: intro-failsafe 0s linear 7s forwards !important; }
  .intro.is-leaving { transition: opacity calc(0.38s * var(--intro-slow)) linear; }
}

/* Narrow screens keep the same choreography at a smaller scale: the card
   geometry is already proportional to --pile-w, so only the wordmark needs
   easing back off the pile. */
@media (max-width: 640px) {
  .intro__stage { --pile-w: clamp(206px, 58vw, 300px); }
  .intro__logo { --mark-h: 44px; }
}

/* ==========================================================================
   DECK ALIGNMENT: components added to carry patterns that exist in the five
   UVEC presentation decks but had no equivalent here. Nothing above this line
   was re-skinned: the palette, type scale and motion vocabulary are unchanged.
   ========================================================================== */

/* ---- Additive tokens ------------------------------------------------------
   Sampled from ppt/theme/theme1.xml and from actual srgbClr usage across the
   142 slides. The site palette already covers navy and cyan, so these exist
   only for the two roles it had no token for: the decks' heading navy (used
   545 times in the renewable deck) and their neutral body greys. */
:root {
  --deck-navy:    #0E2841;  /* theme dk2: dominant deck ground */
  --deck-head:    #002060;  /* deck heading navy */
  --deck-cyan:    #24B7C6;  /* deck accent */
  --deck-cyan-lt: #3CCDDC;  /* deck accent, lighter */
  --deck-grey:    #404040;  /* deck neutral body */
  --deck-grey-dk: #262626;  /* deck neutral, darker */
}

/* ---- Capability figure: the decks' large light numeral over an uppercase
   caption. Deliberately lighter than .stat__num: the decks set these in
   Montserrat Light at 36-72pt, so weight 300 is the honest translation. ---- */
.figure { border-top: 2px solid var(--cyan); padding-top: 18px; }
.figure__num {
  font-weight: 400;
  font-size: clamp(2.5rem, 4.8vw, 4.1rem);
  line-height: 1;
  color: var(--brand);
  letter-spacing: -0.01em;
  font-family: var(--serif);}
.figure__cap {
  margin-top: 10px;
  font-size: 0.76rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--navy);
}
.figgrid { display: grid; grid-template-columns: repeat(5, 1fr); gap: clamp(20px, 3vw, 48px); }
.figgrid--four  { grid-template-columns: repeat(4, 1fr); }
.figgrid--eight { grid-template-columns: repeat(4, 1fr); }
.statband .figure { border-top-color: var(--cyan); }
.statband .figure__num { color: #fff; }
.statband .figure__cap { color: var(--cyan); }

/* ---- Presence: HEADQUARTERS / REGIONAL OFFICES / WHERE WE ARE WORKING ---- */
.presence { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(22px, 3vw, 48px); }
.presence__item { border-top: 1px solid var(--dark-12); padding-top: 20px; }
.presence__label {
  font-size: 0.72rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--navy);
}
.presence__value {
  margin-top: 12px; font-weight: 400; color: var(--ink);
  font-size: clamp(1.5rem, 2.6vw, 2.2rem); line-height: 1.2;
  font-family: var(--serif);}
.section--navy .presence__item { border-top-color: var(--white-12); }
.section--navy .presence__label { color: var(--cyan); }
.section--navy .presence__value { color: #fff; }

/* ---- Capability card: figure + photo + sub-capability list ---------------- */
.caps { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 2.6vw, 34px); }
.cap {
  display: flex; flex-direction: column;
  background: var(--white); border: 1px solid var(--line);
  border-radius: 6px; overflow: hidden;
  transition: transform var(--dur-med) var(--ease-out), box-shadow var(--dur-med) var(--ease-out);
}
.cap:hover { transform: translateY(-4px); box-shadow: 0 18px 44px rgba(5,10,24,0.10); }
.cap__media { aspect-ratio: 16 / 10; overflow: hidden; background: var(--paper); }
.cap__media img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-slow) var(--ease-out); }
.cap:hover .cap__media img { transform: scale(1.04); }
.cap__body { padding: clamp(22px, 2.4vw, 32px); display: flex; flex-direction: column; flex: 1 1 auto; }
.cap__num { font-weight: 400; font-size: clamp(2rem, 3.4vw, 2.9rem); line-height: 1; color: var(--brand); font-family: var(--serif);}
.cap__title {
  margin-top: 8px; font-size: 0.78rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--navy);
}
.cap__list { list-style: none; margin: 18px 0 0; padding: 0; }
.cap__list li {
  position: relative; padding-left: 16px; margin-bottom: 7px;
  color: var(--muted); font-weight: 300; font-size: 0.93rem;
}
.cap__list li::before {
  content: ''; position: absolute; left: 0; top: 0.62em;
  width: 6px; height: 6px; background: var(--cyan); border-radius: 50%;
}

/* ---- Two-column service matrix, preserving the decks' own pairings ------- */
.svcmx { border-top: 1px solid var(--dark-12); }
.svcmx__row {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(14px, 3vw, 48px);
  padding: clamp(13px, 1.5vw, 18px) 4px; border-bottom: 1px solid var(--dark-12);
}
.svcmx__cell { color: var(--ink); font-weight: 400; font-size: 0.97rem; }
.svcmx__cell--empty { color: var(--muted); }

/* ---- Framework agreement / approval card -------------------------------- */
.fwgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2vw, 26px); }
.fw {
  background: var(--white); border: 1px solid var(--line); border-radius: 6px;
  padding: clamp(20px, 2.2vw, 28px); display: flex; flex-direction: column;
}
.fw__logo { height: 46px; display: flex; align-items: center; margin-bottom: 18px; }
.fw__logo img { max-height: 100%; max-width: 100%; width: auto; object-fit: contain; }
.fw__term {
  font-size: 0.72rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--navy); padding-bottom: 14px; border-bottom: 1px solid var(--line); margin-bottom: 14px;
}
.fw__stats { list-style: none; margin: 0; padding: 0; }
.fw__stats li { margin-bottom: 12px; }
.fw__stat-num { display: block; font-weight: 400; font-size: 1.8rem; line-height: 1.1; color: var(--brand); font-family: var(--serif);}
.fw__stat-cap { display: block; margin-top: 2px; color: var(--muted); font-weight: 300; font-size: 0.87rem; }

/* ---- Project group divider, one per deck separator slide ---------------- */
/* Light bands. The scrim over the divider photograph is white rather than navy,
   so the aerial reads as a pale wash under the heading instead of a solid navy
   block. Type goes to brand navy with it: white-on-white is not a scrim, it is
   an erasure. The hairline is what a navy band did not need and a white one
   does — without it the band has no edge against the white sections it sits
   between. */
.groupband {
  position: relative; overflow: hidden; background: var(--white);
  border-block: 1px solid var(--line);
}
/* Held back only as far as the type needs: a wash heavy enough to read
   through is a wash that has erased the photograph. The gradient stays
   strongest under the title on the left and thins to almost nothing on the
   right, so the picture is a picture again by the time it clears the words. */
.groupband__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to right, rgba(255,255,255,0.72) 0%, rgba(255,255,255,0.40) 55%, rgba(255,255,255,0.14) 100%);
}
.groupband__bg { position: absolute; inset: 0; }
.groupband__bg img { width: 100%; height: 100%; object-fit: cover; opacity: 0.92; }
.groupband__inner {
  position: relative; padding-block: clamp(38px, 5vw, 64px);
  padding-inline: var(--pad-x); max-width: var(--maxw); margin-inline: auto;
}
.groupband__title {
  color: var(--brand); font-weight: 500; letter-spacing: -0.01em;
  line-height: 1.12; font-size: clamp(1.6rem, 3.4vw, 2.6rem); margin: 0;
  font-family: var(--serif);}
.groupband__count {
  /* Cyan was legible on navy and is not legible on white; navy carries the
     same hierarchy at this weight and size. */
  display: block; margin-top: 10px; color: var(--navy);
  font-size: 0.74rem; font-weight: 400; letter-spacing: 0.16em; text-transform: uppercase;
}

/* ---- Team-reference badge ------------------------------------------------ */
.badge {
  display: inline-block; padding: 4px 10px; border-radius: 999px;
  font-size: 0.62rem; font-weight: 400; letter-spacing: 0.14em; text-transform: uppercase;
  border: 1px solid currentColor;
}
.pcard { position: relative; }
.pmodal__badges { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.pmodal__note {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  color: var(--muted); font-weight: 300; font-size: 0.86rem;
}

/* ---- The five deck project fields: Role, Country, Key Specs, Year, Scope
   Rendered in the decks' order, never reordered or dropped. Key Specs and
   Scope are multi-line in the source and become lists here. ---------------- */
/* One row per field. grid-template-columns is set explicitly because this list
   used to also carry .pmodal__facts, whose three-column grid squeezed each row
   into a narrow track and stacked the words one under the other. */
.projfields {
  display: grid; grid-template-columns: 1fr; gap: 0;
  border-top: 1px solid var(--line); margin: 0; min-width: 0;
}
.projfields > div {
  display: grid; grid-template-columns: 132px minmax(0, 1fr);
  gap: clamp(14px, 2vw, 30px); padding: 14px 0; border-bottom: 1px solid var(--line);
  align-items: start; min-width: 0;
}
.projfields dt {
  font-size: 0.68rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--navy); padding-top: 3px;
}
.projfields dd { margin: 0; min-width: 0; color: var(--ink); font-weight: 400; font-size: 0.95rem; line-height: 1.6; }
.projfields dd ul { list-style: none; margin: 0; padding: 0; }
.projfields dd ul li {
  position: relative; padding-left: 15px; margin-bottom: 6px; font-weight: 300; color: var(--body);
}
.projfields dd ul li:last-child { margin-bottom: 0; }
.projfields dd ul li::before {
  content: ''; position: absolute; left: 0; top: 0.6em;
  width: 5px; height: 5px; background: var(--cyan); border-radius: 50%;
}
.projfields dd.is-empty { color: var(--muted); font-weight: 300; }

/* ---- Partner block ----------------------------------------------------- */
.partner {
  display: grid; grid-template-columns: 190px minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px); align-items: start;
}
.partner__logo {
  background: var(--white); border: 1px solid var(--line); border-radius: 6px;
  padding: 22px; display: flex; align-items: center; justify-content: center; min-height: 132px;
}
.partner__logo img { max-width: 100%; height: auto; }
.partner__feat { list-style: none; margin: 22px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px clamp(20px, 3vw, 40px); }
.partner__feat li { border-top: 1px solid var(--dark-12); padding-top: 12px; }
.partner__feat-name {
  display: block; font-size: 0.72rem; font-weight: 400; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--navy);
}
.partner__feat-val { display: block; margin-top: 5px; font-weight: 300; color: var(--ink); font-size: 1.05rem; }
/* One label over a list, rather than the same label repeated eight times down
   the column: the word was doing no work after the first row. */
.partner__feat-head { margin: 22px 0 0; }
.partner__list {
  list-style: none; margin: 12px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(20px, 3vw, 48px);
}
.partner__list li {
  border-top: 1px solid var(--dark-12);
  padding: 12px 0;
  font-weight: 300; color: var(--ink); font-size: 0.98rem; line-height: 1.45;
}
@media (max-width: 760px) { .partner__list { grid-template-columns: 1fr; } }
.partner__feat-where { display: block; margin-top: 2px; color: var(--muted); font-weight: 300; font-size: 0.86rem; }

/* ---- Digital product: the deck's three solutions ----------------------- */
.dprod-grid--three { grid-template-columns: repeat(3, 1fr); }

/* ---- Filter dropdowns -------------------------------------------------- */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: end;
  gap: clamp(16px, 2.4vw, 32px);
}
.filterbar__field { display: flex; flex-direction: column; min-width: 0; flex: 0 1 260px; }
.filterbar__label {
  margin-bottom: 9px;
  font-size: 0.68rem; font-weight: 400; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted);
}
.filterbar__select {
  appearance: none; -webkit-appearance: none;
  width: 100%; padding: 12px 42px 12px 16px;
  font-family: inherit; font-size: 0.92rem; font-weight: 400; color: var(--ink);
  background-color: var(--white);
  border: 1px solid var(--line); border-radius: 4px;
  cursor: pointer;
  /* chevron drawn as a background so no extra element is needed */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23003366' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px 16px;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
.filterbar__select:hover { border-color: var(--navy); }
.filterbar__select:focus-visible {
  outline: none; border-color: var(--navy);
  box-shadow: 0 0 0 3px var(--cyan-14);
}
.filterbar__count {
  flex: 1 1 auto; min-width: 0; margin: 0 0 12px;
  color: var(--muted); font-weight: 300; font-size: 0.9rem; text-align: right;
}

.pcard.is-hidden { display: none; }
/* A whole group filtered out. initFilters() has always put .is-hidden on the
   divider and on its card grid when nothing in the group survives the filter,
   but the class had no rule outside .pcard: so the band stayed, and the empty
   grid under it kept its padding. A heading over nothing, with a hole beneath. */
.groupband.is-hidden,
.section[data-group-body].is-hidden { display: none; }
.filter-count { color: var(--muted); font-weight: 300; font-size: 0.9rem; }

/* ---- Responsive ------------------------------------------------------- */
@media (max-width: 1180px) {
  .figgrid, .figgrid--four { grid-template-columns: repeat(3, 1fr); }
  .figgrid--eight { grid-template-columns: repeat(4, 1fr); }
  .caps { grid-template-columns: repeat(2, 1fr); }
  .dprod-grid--three { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 860px) {
  .filterbar { flex-direction: column; align-items: stretch; }
  .filterbar__field { flex: 1 1 auto; }
  .filterbar__count { text-align: left; margin-bottom: 0; }
  .figgrid, .figgrid--four, .figgrid--eight { grid-template-columns: repeat(2, 1fr); }
  .presence { grid-template-columns: 1fr; }
  .caps { grid-template-columns: 1fr; }
  .fwgrid { grid-template-columns: repeat(2, 1fr); }
  .dprod-grid--three { grid-template-columns: 1fr; }
  .partner { grid-template-columns: 1fr; }
  .partner__logo { max-width: 190px; }
  .partner__feat { grid-template-columns: 1fr; }
  .svcmx__row { grid-template-columns: 1fr; gap: 6px; }
  .svcmx__cell--empty { display: none; }
  .projfields > div { grid-template-columns: 1fr; gap: 6px; padding: 13px 0; }
}
@media (max-width: 520px) {
  .figgrid, .figgrid--four, .figgrid--eight { grid-template-columns: 1fr; }
  .fwgrid { grid-template-columns: 1fr; }
}

/* The decks set these figures as single units ("2300 MWp", "+1700 MWh"), so they
   must not break across lines. Sized to fit a five-column track at 1440. */
.figure__num, .cap__num, .fw__stat-num { white-space: nowrap; }
.figgrid .figure__num { font-size: clamp(1.75rem, 2.5vw, 2.5rem); }
@media (max-width: 860px) {
  .figgrid .figure__num { font-size: clamp(1.9rem, 6vw, 2.5rem); }
}

/* Waste-to-energy is the one capability the decks give no headline figure for.
   Its card leads with the name at the figure's size rather than inventing one. */
.cap__title--lead {
  font-size: clamp(1.35rem, 2.2vw, 1.85rem);
  font-weight: 300;
  letter-spacing: 0;
  text-transform: none;
  color: var(--brand);
  line-height: 1.15;
}

/* The reset zeroes paragraph margins, which is right for the single-paragraph
   blocks the rest of the site uses. The deck's About UVEC copy is four
   consecutive paragraphs, so they need to be separated. */
.editorial__prose p + p,
.prose-stack p + p,
.lead + .lead { margin-top: 14px; }

/* The footer now carries an email and a phone number. They were inline-block,
   so the two ran together on one line; each takes its own line, with the cyan
   underline still hugging the text rather than the column. */
.footer__email { display: block; width: fit-content; }
.footer__email + .footer__email { margin-top: 8px; }

/* ---- Nav dropdown -------------------------------------------------------
   About Us groups its own page and Expertise. The parent is still a real link,
   so it works with JavaScript off and for anyone who taps rather than hovers;
   the menu opens on hover, on focus and on click. */
.navdrop { position: relative; display: flex; align-items: center; }
.navdrop__toggle { display: inline-flex; align-items: center; gap: 6px; }
.navdrop__chev {
  width: 13px; height: 13px; stroke: currentColor;
  transition: transform var(--dur-fast) var(--ease-out);
}
.navdrop__menu {
  position: absolute; top: 100%; left: -18px; z-index: 60;
  min-width: 208px; margin: 0; padding: 8px;
  list-style: none;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 18px 44px rgba(5,10,24,0.16);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out),
              visibility var(--dur-fast) var(--ease-out);
}
/* A hover bridge so the pointer can cross the gap without the menu closing. */
.navdrop::after {
  content: ""; position: absolute; top: 100%; left: 0; right: 0; height: 14px;
}
.navdrop:hover .navdrop__menu,
.navdrop:focus-within .navdrop__menu,
.navdrop.is-open .navdrop__menu {
  opacity: 1; visibility: visible; transform: none;
}
.navdrop:hover .navdrop__chev,
.navdrop.is-open .navdrop__chev { transform: rotate(180deg); }
.navdrop__link {
  display: block; padding: 9px 12px; border-radius: 4px;
  font-size: 0.8rem; font-weight: 400; color: var(--ink);
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.navdrop__link:hover, .navdrop__link:focus-visible { background: var(--paper); color: var(--navy); }
.navdrop__link[aria-current="page"] { color: var(--navy); background: var(--cyan-14); }
.nav__link.is-active::after { transform: scaleX(1); }
.mnav__link--sub { padding-left: clamp(30px, 6vw, 56px); opacity: 0.86; }

/* ---- The tagline: the deck sets its second half in italic --------------- */
.tagline__em, .eyebrow__em, .footer__quote-em, .hero__title-em {
  font-style: italic;
  font-family: inherit;
}
.hero__title-em { color: var(--cyan); font-weight: 500; }
.eyebrow__em { color: inherit; }
/* The tagline is set in two colours: the statement in the logo navy and the
   promise in the brand cyan, italic. */
.footer__quote-em { color: var(--cyan); }

/* ---- UVEC Presence over the deck's world map --------------------------- */
.presence-band {
  position: relative; overflow: hidden;
  padding-block: clamp(56px, 7vw, 104px);
  background: linear-gradient(150deg, var(--brand) 0%, var(--navy) 100%);
}
.presence-band__map { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.presence-band__map img {
  /* cover, not contain: the band is much wider than the artwork is tall, and
     letterboxing left the map floating small in the middle of it. The crop
     only takes the empty polar margins. */
  width: 100%; height: 100%; object-fit: cover; object-position: center 42%;
  /* The map arrives in the deck's own navy. Lifted to a pale tint so it reads
     as a ground behind the type rather than competing with it. */
  filter: brightness(0) invert(1) opacity(0.26);
}
.presence-band__inner { position: relative; z-index: 2; }
.presence-band .presence__item { border-top-color: var(--white-40); }
.presence-band .presence__label { color: var(--cyan); }
.presence-band .presence__value { color: #fff; }
@media (max-width: 860px) {
  .presence-band__map img { object-fit: cover; filter: brightness(0) invert(1) opacity(0.14); }
}

