/**
 * Zouma Theme — layout & components.
 *
 * Design tokens live in style.css.
 */

/* Layout shell ---------------------------------------------------------- */

.zouma-shell {
  width: 100%;
  max-width: 1320px;
  margin-inline: auto;
  padding-inline: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
  /* Never wider than the space it is given.
   *
   * `main > section` is a grid, so every shell is a grid item and carries
   * the automatic min-width: auto floor — it refuses to shrink below its
   * content's min-content width. Any section holding something that does not
   * wrap (a tab rail, a marquee, a long unbroken string) therefore pushed the
   * shell open: the pillars shell measured 444px inside a 390px phone, and
   * .zouma-site clips on the x axis, so it failed silently — the tabs were
   * simply cut off with no scrollbar to reveal them.
   *
   * width: 100% loses to that floor; min-width: 0 releases it, and the
   * scrollers inside then do their own job. Two sections already patched
   * this one at a time (.zouma-indlist, .zouma-indways); this makes it the
   * rule rather than a list of exceptions. */
  min-width: 0;
}

.zouma-site {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* `clip`, not `hidden`. `overflow-x: hidden` forces the other axis to `auto`,
	 * which turns this into a scroll container and silently kills the sticky
	 * header inside it. `clip` trims the same overhang without that side effect. */
  overflow-x: clip;
}

.zouma-main {
  flex: 1 0 auto;
  padding-block: 0;
}

.zouma-dark {
  background: var(--zouma-dark);
  color: #fff;
}

.zouma-dark h1,
.zouma-dark h2,
.zouma-dark h3 {
  color: #fff;
}

/* Shared type ----------------------------------------------------------- */

/* The icon and the word sit on one level line.
 *
 * The mark is an <img>, and with no display set here the eyebrow was a block
 * and the image an inline box — so it was aligned on the text's baseline. A
 * baseline puts the image's bottom edge where the letters' feet are, which
 * lifts a 20px square well above the middle of a 12px capital: measured at
 * 7.2px too high on the homepage and 5.2px on the pillar rows.
 *
 * inline-flex with centred items instead. Most sections already declare this
 * for themselves — About, Careers, Contact, the hero bands — and those all
 * measured level; the ones that read crooked were exactly the ones relying on
 * this shared rule. Stating it here fixes them together and leaves the rest
 * untouched, since a section's own rule still outranks it.
 *
 * inline-flex rather than flex so the box still shrinks to its content and a
 * centred parent goes on centring it, which a full-width flex block would not.
 *
 * The gap has to be declared: flex drops the whitespace between the tags that
 * was providing the 4.3px separation. 8px is what every section that sets its
 * own eyebrow already uses. */
.zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 1rem;
  color: var(--zouma-blue);
  font-size: var(--zouma-size-eyebrow);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.zouma-eyebrow--light {
  color: var(--zouma-accent);
}

.zouma-section-title {
  max-width: 24ch;
  margin: 0 0 1rem;
  font-size: var(--zouma-size-h2);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.zouma-section-title--center {
  max-width: 26ch;
  margin-inline: auto;
  text-align: center;
}

.zouma-lede {
  max-width: 62ch;
  margin: 0 0 2rem;
  color: var(--zouma-color-muted);
  font-size: var(--zouma-size-lede);
}

.zouma-dark .zouma-lede {
  color: rgba(255, 255, 255, 0.72);
}

.zouma-lede--center {
  margin-inline: auto;
  text-align: center;
}

/* Buttons --------------------------------------------------------------- */

.zouma-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.8rem 1.4rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background var(--zouma-transition),
    color var(--zouma-transition),
    border-color var(--zouma-transition),
    transform var(--zouma-transition);
}

.zouma-btn:hover {
  transform: translateY(-1px);
}

.zouma-btn__arrow {
  transition: transform var(--zouma-transition);
}

.zouma-btn:hover .zouma-btn__arrow {
  transform: translateX(3px);
}

.zouma-btn--primary {
  background: var(--zouma-blue);
  color: #fff;
}

.zouma-btn--primary:hover {
  background: var(--zouma-blue-dark);
  color: #fff;
}

.zouma-btn--ghost {
  background: transparent;
  color: var(--zouma-color-text);
  border-color: var(--zouma-color-border);
}

.zouma-btn--ghost:hover {
  background: var(--zouma-blue-pale);
  color: var(--zouma-blue-dark);
  border-color: transparent;
}

.zouma-dark .zouma-btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.28);
}

.zouma-dark .zouma-btn--ghost:hover {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
}

.zouma-btn--light {
  background: #fff;
  color: var(--zouma-dark);
}

.zouma-btn--light:hover {
  background: var(--zouma-blue-pale);
  color: var(--zouma-dark);
}

/* Header — superseded first pass removed.
 *
 * These rules were replaced by the rebuilt header further down, but only
 * partly overridden, so they kept leaking through: a near-black pill fill that
 * fought the glass bar, and a max-height of 30px on the logo that silently
 * clamped the 40px set later. .zouma-header__mark and __word went with them —
 * no template has referenced either since the header was rebuilt.
 */

/* Navigation ------------------------------------------------------------ */

.zouma-nav__list,
.zouma-nav__list ul {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zouma-nav__list > li {
  position: relative;
}

.zouma-nav__list a {
  display: block;
  padding: 0.35rem 0;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.87rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--zouma-transition);
}

.zouma-nav__list a:hover,
.zouma-nav__list .current-menu-item > a,
.zouma-nav__list .current_page_item > a {
  color: #fff;
}

.zouma-nav__list .sub-menu {
  position: absolute;
  top: calc(100% + 0.6rem);
  left: 0;
  z-index: 10;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  min-width: 13rem;
  padding: 0.5rem;
  background: var(--zouma-teal-deep);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 0.75rem;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35);
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition:
    opacity var(--zouma-transition),
    transform var(--zouma-transition),
    visibility var(--zouma-transition);
}

.zouma-nav__list li:hover > .sub-menu,
.zouma-nav__list li:focus-within > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.zouma-nav__list .sub-menu a {
  padding: 0.5rem 0.7rem;
  border-radius: 0.4rem;
}

.zouma-nav__list .sub-menu a:hover {
  background: rgba(255, 255, 255, 0.08);
}

.zouma-nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border: 0;
  border-radius: 999px;
}

.zouma-nav-toggle__bars,
.zouma-nav-toggle__bars::before,
.zouma-nav-toggle__bars::after {
  display: block;
  width: 16px;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition:
    transform var(--zouma-transition),
    opacity var(--zouma-transition);
}

.zouma-nav-toggle__bars {
  position: relative;
}

.zouma-nav-toggle__bars::before,
.zouma-nav-toggle__bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.zouma-nav-toggle__bars::before {
  top: -5px;
}
.zouma-nav-toggle__bars::after {
  top: 5px;
}

.zouma-nav-toggle[aria-expanded="true"] .zouma-nav-toggle__bars {
  background: transparent;
}
.zouma-nav-toggle[aria-expanded="true"] .zouma-nav-toggle__bars::before {
  transform: translateY(5px) rotate(45deg);
}
.zouma-nav-toggle[aria-expanded="true"] .zouma-nav-toggle__bars::after {
  transform: translateY(-5px) rotate(-45deg);
}

@media (max-width: 1080px) {
  .zouma-nav {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
    right: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
    display: none;
    padding: 1rem;
    background: var(--zouma-dark);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 1.25rem;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.3);
  }

  /* Bounded to the screen, and scrolled inside itself.
	 *
	 * The panel hangs off the sticky header, so it never moves when the page
	 * does — anything past the bottom of the viewport simply cannot be reached.
	 * On a landscape phone that was eight of the fifteen links, Contact Us
	 * among them: the menu opened, and half of it was unreachable by any
	 * gesture. Capped to the space actually below the header instead.
	 *
	 * svh rather than vh, with vh first for browsers that do not know it: on a
	 * phone vh is the height with the browser chrome retracted, which is taller
	 * than what the visitor can see at the moment the menu opens. */
  .zouma-nav.is-open {
    display: block;
    max-height: calc(100vh - var(--zouma-header-h) - 2rem);
    max-height: calc(100svh - var(--zouma-header-h) - 2rem);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .zouma-nav__list,
  .zouma-nav__list .sub-menu {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
  }

  .zouma-nav__list .sub-menu {
    position: static;
    width: 100%;
    padding: 0 0 0 0.9rem;
    background: transparent;
    border: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .zouma-nav-toggle {
    display: inline-flex;
  }

  .zouma-header__cta {
    display: none;
  }
}

/* 03 · Stats ------------------------------------------------------------- */

.zouma-stats {
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 6rem);
  text-align: center;
}

.zouma-stats .zouma-section-title {
  max-width: 30ch;
  margin-inline: auto;
  margin-bottom: clamp(2rem, calc(4 * var(--zouma-vw)), 3.5rem);
}

/* The grid itself — superseded; the section is rebuilt further down.
 *
 * Unlike the other superseded blocks, this one was still reaching the page.
 * The rebuild reuses the same class names and only restates the properties it
 * needed, so everything this rule set declared and that one did not carried
 * straight through: a 1px border with a 16px radius and overflow: hidden drew
 * a rounded card around the figures, and a right and bottom border on every
 * cell ruled it like a table — both sitting on top of the vlines, hlines and
 * dots the rebuild draws, which are the actual design.
 *
 * It was also throwing the drawn rules out of true. This capped the grid at
 * 60rem inside a 978px frame, and the rules are positioned on the frame — so
 * the lines were laid out for one width and the columns for another, 18px
 * apart. Removing it puts them back on the same measure.
 *
 * Deleted rather than overridden, so the next person to reuse these names does
 * not have to find it a second time. */

/* 04 · Instinct — superseded; the section is rebuilt further down. ------- */

.zouma-instinct__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(2rem, calc(5 * var(--zouma-vw)), 4rem);
  align-items: center;
}

.zouma-instinct__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 2rem;
  margin: 2rem 0 0;
  padding: 0;
  list-style: none;
}

.zouma-instinct__list h3 {
  margin: 0 0 0.4rem;
  font-size: 1rem;
  font-weight: 600;
}

.zouma-instinct__list p {
  margin: 0;
  color: rgba(255, 255, 255, 0.65);
  font-size: var(--zouma-size-body);
}

.zouma-orbit {
  position: relative;
  aspect-ratio: 1;
  max-width: 26rem;
  margin-inline: auto;
}

.zouma-orbit::before,
.zouma-orbit::after {
  content: "";
  position: absolute;
  inset: 12%;
  border: 1px solid rgba(43, 174, 228, 0.22);
  border-radius: 50%;
}

.zouma-orbit::after {
  inset: 28%;
  border-color: rgba(43, 174, 228, 0.35);
}

.zouma-orbit__core {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 34%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle at 30% 30%, #5fc0ea, var(--zouma-blue));
  border-radius: 50%;
  box-shadow: 0 0 60px rgba(43, 174, 228, 0.45);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.1em;
}

.zouma-orbit__node {
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--zouma-accent);
  border-radius: 50%;
  box-shadow: 0 0 0 6px rgba(43, 174, 228, 0.15);
}

.zouma-orbit__node--1 {
  top: 10%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.zouma-orbit__node--2 {
  top: 50%;
  left: 90%;
  transform: translate(-50%, -50%);
}
.zouma-orbit__node--3 {
  top: 90%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.zouma-orbit__node--4 {
  top: 50%;
  left: 10%;
  transform: translate(-50%, -50%);
}

/* 09 · Standards ----------------------------------------------------------
 *   Copy block left, the commitments listed out in full on the right.
 *
 * These used to be an accordion. They are six short statements of intent, all
 * of similar weight and none of them the answer to a question — the reason to
 * read one is the same as the reason to read the next, so hiding five behind a
 * click only made the section look emptier than it is. The list shows them
 * all.
 *
 *   split    0.65fr / 1fr, gap 4rem
 *   rows     rule above each · 38% title column · 3% gutter
 *   type     title 1rem/600 white · text 0.8125rem/1.6 at 62% white
 */

.zouma-standards {
  position: relative;
  /* clip, not hidden: the copy column opposite is sticky, and `overflow: hidden`
   * on an ancestor makes that ancestor a scroll container, which confines the
   * sticky element to a box that never scrolls — so it simply would not stick.
   * `clip` clips exactly the same way without creating one. (.zouma-site above
   * already uses clip for its own reasons.) */
  overflow: clip;
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 6.5rem);
}

/* Same device as the intro statement: one wide ellipse rising from below the
 * foot of the section, which lifts the dark panel off flat black. */
.zouma-standards__glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: radial-gradient(
    ellipse 58% 54% at 42% 114%,
    rgba(14, 133, 182, 0.5) 0%,
    rgba(14, 133, 182, 0.16) 44%,
    rgba(14, 133, 182, 0) 74%
  );
  pointer-events: none;
}

.zouma-standards__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 0.65fr) minmax(0, 1fr);
  gap: clamp(2rem, calc(5 * var(--zouma-vw)), 4rem);
  align-items: start;
}

/* The copy rides down with the reader.
 *
 * The commitments list opposite is roughly three times the height of this
 * column, so without this the heading scrolls away and the rows lose the thing
 * they are answering. As a grid item it sticks within its own grid area, which
 * is the full height of the row, so it releases again at the foot of the list
 * rather than escaping the section.
 *
 * The offset clears the sticky site header; sticky is switched off below where
 * the grid collapses to one column. */
.zouma-standards__copy {
  position: sticky;
  /* Clear of the header's scrim, not just the header.
   *
   * .zouma-header::before extends 2.25rem past the bar (inset: 0 0 -2.25rem)
   * and carries the fill and the backdrop blur, so the band that obscures the
   * page reaches ~112px, not the 76px the header box measures. Pinning at
   * 76 + 24 put the eyebrow inside that band, and OUR COMMITMENTS washed out
   * under the blur as soon as the copy stuck — the heading below it cleared,
   * which is why only the eyebrow went missing.
   *
   * 76 + 56 clears the scrim with room to spare. */
  top: calc(var(--zouma-header-h, 76px) + 3.5rem);
}

/* Copy block. The eyebrow follows the same icon-plus-label pattern as every
 * other section head; the lede is a step smaller here than the shared token,
 * so it reads as a caption under the heading rather than competing with the
 * list opposite. */
.zouma-standards .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 1.25rem;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-standards .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-standards .zouma-section-title {
  max-width: 24ch;
  margin: 0 0 1.125rem;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-weight: 700;
  /* No line-height here. This selector is (0,2,0) and outranks the shared
	 * h2.class rule, so declaring one would quietly opt this heading out of
	 * the site-wide 105%. */
  letter-spacing: -0.02em;
}

.zouma-standards .zouma-lede {
  max-width: 40ch;
  margin: 0;
  color: rgba(255, 255, 255, 0.62);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.6;
}

.zouma-commitments {
  margin: 0;
}

/* The rule sits on top of each row rather than under it, so the list opens
 * with a line and closes without a stray one under the last item. */
.zouma-commitments__row {
  position: relative;
  display: grid;
  grid-template-columns: 38% minmax(0, 1fr);
  column-gap: 3%;
  align-items: start;
  padding-block: clamp(1.25rem, calc(2.2 * var(--zouma-vw)), 1.875rem);
  border-top: 1px solid rgba(255, 255, 255, 0.13);
}

/* No fill on hover. The row is marked by its type coming up and the rule above
 * it sweeping across — nothing is drawn behind it. The gutter and radius that
 * the old blue card needed went with it, so the columns measure from the same
 * edges the rest of the list does. */

/* The sweep.
 *
 * A second line laid over the border rather than the border itself animating:
 * a border cannot be drawn progressively, and animating its width would move
 * the row. This one scales from nothing on the left edge to full width, which
 * runs on the compositor and costs no layout. */
.zouma-commitments__row::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(255, 255, 255, 0.62);
  transform: scaleX(0);
  transform-origin: left center;
  /* 520ms, not 240. At the shorter time the line was already full width by the
	 * time the eye reached it, so it read as switching on rather than as
	 * travelling — the direction, which is the whole point of the gesture, was
	 * invisible. This is still quick, just long enough to see it cross. */
  transition: transform 520ms cubic-bezier(0.33, 0.1, 0.25, 1);
}

.zouma-commitments__row:hover::before {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .zouma-commitments__row::before {
    transition: none;
  }
}

.zouma-commitments__title {
  margin: 0;
  /* Held back from white at rest, so hovering has somewhere to go. */
  color: rgba(255, 255, 255, 0.74);
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  transition: color 220ms ease;
}

.zouma-commitments__text {
  margin: 0;
  color: rgba(255, 255, 255, 0.44);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.6;
  transition: color 220ms ease;
}

.zouma-commitments__row:hover .zouma-commitments__title {
  color: #fff;
}

.zouma-commitments__row:hover .zouma-commitments__text {
  color: rgba(255, 255, 255, 0.86);
}

/* Inner pages ------------------------------------------------------------ */

.zouma-container {
  width: 100%;
  max-width: 1320px;
  margin-inline: auto;
  padding-inline: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
}

.zouma-content > * {
  max-width: var(--zouma-content-width);
  margin-inline: auto;
}

.zouma-content > .alignwide {
  max-width: var(--zouma-wide-width);
}

.zouma-content > .alignfull {
  max-width: none;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
}

.alignleft {
  float: left;
  margin: 0 1rem 1rem 0;
}
.alignright {
  float: right;
  margin: 0 0 1rem 1rem;
}
.aligncenter {
  display: block;
  margin-inline: auto;
}

.zouma-entry-header {
  max-width: var(--zouma-content-width);
  margin: 0 auto 2.5rem;
  padding-top: 3rem;
  text-align: center;
}

.zouma-entry-header__meta,
.zouma-entry-footer {
  color: var(--zouma-color-muted);
  font-size: 0.9rem;
}

.zouma-entry-header__meta > * + *::before {
  content: "·";
  margin: 0 0.4rem;
}

.zouma-post-thumbnail {
  margin-bottom: 2.5rem;
}
.zouma-post-thumbnail img {
  width: 100%;
  border-radius: 1rem;
}

.zouma-entry-footer {
  max-width: var(--zouma-content-width);
  margin: 2.5rem auto 0;
  padding-top: 1rem;
  border-top: 1px solid var(--zouma-color-border);
}

.zouma-page-header {
  padding: 3rem 0 1.5rem;
  border-bottom: 1px solid var(--zouma-color-border);
}

.zouma-posts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
  gap: 1.5rem;
  margin: 2.5rem 0;
}

.zouma-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--zouma-color-border);
  border-radius: 1rem;
  transition:
    transform var(--zouma-transition),
    box-shadow var(--zouma-transition);
}

.zouma-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--zouma-shadow);
}

.zouma-card__media {
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--zouma-color-surface);
}

.zouma-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.zouma-card__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.25rem;
}

.zouma-card__title {
  margin: 0;
  font-size: 1.15rem;
}
.zouma-card__title a {
  color: var(--zouma-color-text);
  text-decoration: none;
}
.zouma-card__title a:hover {
  color: var(--zouma-blue);
}
.zouma-card__excerpt {
  margin: 0;
  color: var(--zouma-color-muted);
  font-size: 0.95rem;
}
.zouma-card__meta {
  margin-top: auto;
  color: var(--zouma-color-muted);
  font-size: 0.85rem;
}

.zouma-pagination {
  margin-bottom: 3rem;
}

.zouma-pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  padding: 0;
  list-style: none;
}

.zouma-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding-inline: 0.6rem;
  border: 1px solid var(--zouma-color-border);
  border-radius: 999px;
  text-decoration: none;
}

.zouma-pagination .page-numbers.current {
  background: var(--zouma-blue);
  border-color: var(--zouma-blue);
  color: #fff;
}

.zouma-post-nav,
.zouma-comments {
  max-width: var(--zouma-content-width);
  margin: 2.5rem auto 0;
}

.zouma-post-nav .nav-links {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1rem;
}

.zouma-post-nav a {
  display: block;
  padding: 1rem;
  border: 1px solid var(--zouma-color-border);
  border-radius: 0.75rem;
  color: var(--zouma-color-text);
  text-decoration: none;
}

.zouma-post-nav a:hover {
  border-color: var(--zouma-blue);
}
.zouma-post-nav .nav-next {
  text-align: right;
}

.zouma-comments {
  margin-bottom: 4rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--zouma-color-border);
}

.zouma-comments .comment-list,
.zouma-comments .comment-list ul {
  padding: 0;
  list-style: none;
}
.zouma-comments .comment-list ul {
  padding-left: 1.5rem;
}
.zouma-comments .comment-body {
  padding: 1rem 0;
  border-bottom: 1px solid var(--zouma-color-border);
}

.zouma-comments .comment-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
}

.zouma-comments .avatar {
  border-radius: 50%;
}
.comment-form p {
  margin-bottom: 1rem;
}

.zouma-search-form {
  display: flex;
  gap: 0.5rem;
  max-width: 28rem;
}

.zouma-404 {
  max-width: var(--zouma-content-width);
  margin-inline: auto;
  padding-block: 4rem;
  text-align: center;
}

.zouma-404__code {
  margin: 0;
  color: var(--zouma-blue);
  font-size: clamp(4rem, calc(12 * var(--zouma-vw)), 8rem);
  line-height: 1;
}

.zouma-widget .widget-title {
  margin-bottom: 0.5rem;
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.zouma-widget ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
.zouma-widget li + li {
  margin-top: 0.25rem;
}

/* Responsive ------------------------------------------------------------- */

@media (max-width: 1024px) {
  .zouma-instinct__inner {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-instinct__diagram {
    order: -1;
  }

  .zouma-standards .zouma-section-title,
  .zouma-standards .zouma-lede {
    max-width: 46ch;
  }

  .zouma-footer__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

/* Commitments: held in two columns further down than the rest.
 *
 * The copy beside this list is sticky, and sticky only travels inside its own
 * grid area. In one column the copy gets a row to itself, exactly its own
 * height, so there is nowhere to travel and it stops holding — which is why
 * the collapse used to take the sticky with it. Keeping the two columns to
 * 860px keeps the copy riding alongside the list on a small laptop, a
 * half-width window, or a zoomed-in browser, where 1024 was cutting it off. */
@media (max-width: 860px) {
  .zouma-standards__inner {
    grid-template-columns: minmax(0, 1fr);
  }

  /* One column now — the copy sits above the list it introduces, so there is
   * nothing for it to ride alongside, and sticky would be inert. */
  .zouma-standards__copy {
    position: static;
  }
}

/* The title column has nowhere to go at this width — the two parts of a
 * commitment stack, title over description. */
@media (max-width: 620px) {
  .zouma-commitments__row {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0.5rem;
  }
}

@media (max-width: 860px) {
  .zouma-statgrid__grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .zouma-statgrid__cell:nth-child(3n) {
    border-right: 1px solid var(--zouma-color-border);
  }
  .zouma-statgrid__cell:nth-child(2n) {
    border-right: 0;
  }
  .zouma-statgrid__cell:nth-last-child(-n + 3) {
    border-bottom: 1px solid var(--zouma-color-border);
  }
  .zouma-statgrid__cell:nth-last-child(-n + 1) {
    border-bottom: 0;
  }

  .zouma-outcomes__cell {
    border-bottom: 1px solid var(--zouma-color-border);
  }
  .zouma-outcomes__cell:nth-child(2n) {
    border-right: 0;
  }

  .zouma-footer__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 560px) {
  .zouma-instinct__list {
    grid-template-columns: minmax(0, 1fr);
  }
  .zouma-statgrid__grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .zouma-statgrid__cell {
    border-right: 0 !important;
  }
}

/* Figma alignment -------------------------------------------------------- */

/* Numerals and display text use Albert Sans; body copy stays Poppins. */
.zouma-statgrid__value,
.zouma-outcomes__value,
.zouma-clock__time,
.zouma-post__number,
.zouma-sunbar__title {
  font-family: var(--zouma-font-heading);
}

/* Section backgrounds, sampled per frame. The standards panel is a deep navy
 * rather than the flat near-black used elsewhere — its glow needs something
 * with a little blue already in it to sit on. */
.zouma-standards {
  background: #05161f;
}
.zouma-footer {
  background: #000;
}

/* The Figma file has a 60px #0E85B6 band between "What we do" and the next
 * section; removed at the client's request. */

.zouma-eyebrow {
  color: var(--zouma-color-muted);
}

.zouma-eyebrow--light {
  color: var(--zouma-sky);
}

.zouma-clock__time {
  font-weight: 600;
  font-size: var(--zouma-size-h3);
}

.zouma-core__card h3 {
  font-family: var(--zouma-font-heading);
  font-weight: 700;
}

/* Verified section fills from the Figma frames. */
.zouma-blog {
  background: var(--zouma-blue-pale);
}
.zouma-footer {
  background: var(--zouma-dark);
}
.zouma-sun,
.zouma-outcomes,
/* "See Open Positions".
 *
 * .zouma-btn--outline has no global definition — it is only given an appearance
 * inside .zouma-404, and .zouma-blog__head sets nothing but flex. Everywhere
 * else the class is a promise the stylesheet never keeps, so this button was
 * falling through to the bare .zouma-btn: a transparent border, a 999px pill
 * and whatever colour the anchor inherited, which is why it read as blue text
 * floating on the white band with no edge at all.
 *
 * Scoped to this section rather than filling in the global variant, because the
 * same unstyled class is also on About Us, Partners and the blog strip, and
 * defining it globally would restyle three pages that were not asked about.
 *
 * The 6px corner is deliberate and departs from the site's pill buttons — it is
 * what the supplied design draws for this one.
 */
.zouma-careers .zouma-btn--outline {
  background: #fff;
  color: var(--zouma-color-text);
  border-color: var(--zouma-color-text);
  border-radius: 6px;
}

/* Fills rather than tints: with a dark hairline already round it, a tint has
 * nowhere to read against, and the arrow follows on currentColor. */
.zouma-careers .zouma-btn--outline:hover,
.zouma-careers .zouma-btn--outline:focus-visible {
  background: var(--zouma-color-text);
  color: #fff;
  border-color: var(--zouma-color-text);
}

.zouma-careers,
.zouma-journey,
.zouma-stats {
  background: #fff;
}

/* Numbered card marker used when a card has no icon. */
.zouma-core__number {
  display: block;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  font-size: var(--zouma-size-h3);
  font-weight: 600;
}

/* Agents-on-shift indicator in the clock cards. */
.zouma-clock__agents {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.5rem 0 0;
  padding: 0.2rem 0.55rem;
  background: var(--zouma-blue-pale);
  border-radius: 999px;
  color: var(--zouma-blue-dark);
  font-size: var(--zouma-size-mini);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.zouma-clock__pulse {
  width: 6px;
  height: 6px;
  background: #22c55e;
  border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.6);
  animation: zouma-pulse 2s infinite;
}

@keyframes zouma-pulse {
  70% {
    box-shadow: 0 0 0 6px rgba(34, 197, 94, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
  }
}

/* =========================================================================
 * Header — matched to the Figma "Container" frame:
 * 1280×69, #042634, 8px radius, 16px padding, 14px/500 Poppins nav.
 * ====================================================================== */

.zouma-header {
  position: sticky;
  top: 0;
  z-index: 200;
  /* Edge to edge. The frosted surface is the header itself now rather than a
	 * pill floating on it, so there is no horizontal padding out here — the bar
	 * inside carries the gutter and keeps the content off the screen edges.
	 *
	 * 8 + 60 + 8 lands on the same 76px --zouma-header-h as the old 16 + 60 + 0,
	 * which is what stops this from shifting the hero: the hero pulls itself up
	 * by that token and pads the same amount back. */
  padding: 0.5rem 0;
  background: transparent;
  transition: padding-top 220ms ease;
}

/* The frosted strip the bar sits on.
 *
 * The bar's own backdrop-filter can only ever show a third of what is behind
 * it — the rest is the fill that keeps the white nav above 4.5:1 — so raising
 * its blur does almost nothing to how frosted the header reads. This is the
 * layer that does that job: full width, no fill of its own, so it is pure blur
 * and costs the nav no contrast at all.
 *
 * Runs past the bar and fades out, rather than stopping on a hard line where
 * the header's box ends. */
.zouma-header::before {
  content: "";
  position: absolute;
  inset: 0 0 -2.25rem;
  z-index: -1;
  pointer-events: none;
  /* This layer is the header's surface: full width, so the frost runs to both
	 * screen edges instead of stopping at a rounded box.
	 *
	 * Fill and blur together, not blur alone. Blur on its own smears the hero
	 * behind into something bright enough to lose white nav text against, and
	 * the gradient is what holds the top of the bar dark enough to read on
	 * while still letting the page show through lower down. */
  background: linear-gradient(
    180deg,
    rgba(6, 11, 15, 0.28) 0%,
    rgba(6, 11, 15, 0.1) 54%,
    rgba(6, 11, 15, 0.02) 84%,
    rgba(6, 11, 15, 0) 100%
  );
  /* Blur raised as the fill came down. They trade off: the fill was doing
	 * most of the work of separating the nav from the page, and with less of it
	 * the smear has to carry more — otherwise what shows through is legible
	 * page content rather than the wash of it the frosted look depends on. */
  -webkit-backdrop-filter: saturate(150%) blur(30px);
  backdrop-filter: saturate(150%) blur(30px);
  /* Fades out rather than ending on a hard line, so the header dissolves into
	 * the page instead of cutting it. The mask takes the fill with it. */
  -webkit-mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 58%, transparent 100%);
}

/* Pages that open on light content — contact, book a call, ESG, the blog, 404.
 *
 * The flat #090B0E swap that used to live here was removed because it made the
 * header read as a different component from page to page: black on some,
 * frosted on others. This keeps the one pane — same gradient shape, same blur,
 * same bottom fade — and only mixes it deeper, because over white the standard
 * fill composites to about 221 and the white nav disappears into it.
 *
 * The treatment is the scrolled one, applied from the top of the page: the
 * same deeper fill, heavier blur and shorter fade that .is-stuck already uses.
 * These pages therefore look the same resting as they do scrolled, which is
 * the point — the bar reads as a bar rather than dissolving into the page. */
body.zouma-light-hero .zouma-header::before {
  background: linear-gradient(
    180deg,
    rgba(6, 11, 15, 0.4) 0%,
    rgba(6, 11, 15, 0.18) 60%,
    rgba(6, 11, 15, 0.03) 86%,
    rgba(6, 11, 15, 0) 100%
  );
  -webkit-backdrop-filter: saturate(160%) blur(34px);
  backdrop-filter: saturate(160%) blur(34px);
  -webkit-mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
  box-shadow: 0 10px 30px rgba(2, 14, 20, 0.34);
}

/* The admin bar is fixed over the top of the page, so drop the header below it
 * for logged-in users. */
.admin-bar .zouma-header {
  top: 32px;
}

@media screen and (max-width: 782px) {
  .admin-bar .zouma-header {
    top: 46px;
  }
}

/* Once the page has scrolled the bar tucks closer to the top edge and picks up
 * a shadow, so it reads as floating over the content rather than part of it. */
/* Scrolled. The bar keeps its height and its full width — what changes is how
 * much page it lets through. Content is running under it by now rather than the
 * hero's quiet top edge, so the fill deepens and the fade shortens to hold the
 * nav legible over whatever happens to be passing. */
.zouma-header.is-stuck::before {
  background: linear-gradient(
    180deg,
    rgba(6, 11, 15, 0.4) 0%,
    rgba(6, 11, 15, 0.18) 60%,
    rgba(6, 11, 15, 0.03) 86%,
    rgba(6, 11, 15, 0) 100%
  );
  -webkit-backdrop-filter: saturate(160%) blur(34px);
  backdrop-filter: saturate(160%) blur(34px);
  -webkit-mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
  box-shadow: 0 10px 30px rgba(2, 14, 20, 0.34);
}

.zouma-header__bar {
  display: flex;
  align-items: center;
  /* One centred cluster, not three items pushed to the edges. space-between
	 * stretches the logo to the far left and the CTA to the far right, which on
	 * a wide screen leaves the nav marooned in the middle with a gap either
	 * side of it. Centring keeps logo, nav and actions reading as a single
	 * group with even air around it, at any width. */
  justify-content: center;
  gap: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
  /* Only a maximum, and only so the group cannot sprawl on a very wide
	 * display — the cluster is usually narrower than this and centres inside
	 * it, which is the same as centring on the screen. */
  max-width: 1560px;
  /* 60px rather than 69: the bar sits tighter than it did, and the padding
	 * above it comes down to match. --zouma-header-h tracks the pair. */
  min-height: 60px;
  margin-inline: auto;
  padding: 0 clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
  /* Fill, blur and hairline have all moved out to .zouma-header::before so
	 * they can run the full width of the screen. What is left here is layout:
	 * the bar is now just the row the content sits in. */
  background-color: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Without backdrop-filter there is no wash to hide behind, so the fill has to
 * carry legibility on its own. */
@supports not (
  (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))
) {
  .zouma-header::before {
    background: linear-gradient(
      180deg,
      #031219f5 0%,
      #042634e6 58%,
      #04263400 100%
    );
  }
}

.zouma-header__logo {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  text-decoration: none;
}

.zouma-header__logo img {
  display: block;
  width: auto;
  height: 40px;
}

.zouma-header__actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-left: 0;
  flex: 0 0 auto;
}

/* Nav ------------------------------------------------------------------- */

.zouma-nav__list,
.zouma-nav__list ul {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zouma-nav__list a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--zouma-transition);
}

.zouma-nav__list a:hover,
.zouma-nav__list .current-menu-item > a,
.zouma-nav__list .current_page_item > a {
  color: var(--zouma-cyan);
}

.zouma-icon {
  flex: 0 0 auto;
}

/* The cluster mark is always brand cyan. As a raster it carried its own colour
 * and every section had to be told nothing; drawn as an SVG it inherits
 * currentColor instead, so it needs a default here or it would take whatever
 * colour the eyebrow around it happens to be. Section rules still override. */
.zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-icon--caret {
  width: 16px;
  height: 16px;
  transition: transform var(--zouma-transition);
}

.zouma-nav__list li:hover > a .zouma-icon--caret {
  transform: rotate(180deg);
}

/* Label-only parents ------------------------------------------------------
 *
 * Company opens its submenu but goes nowhere, so the walker renders it as a
 * button rather than a link. That has to be undone visually: style.css gives
 * every bare <button> a filled primary pill, and its button:hover turns it
 * dark blue. Both are matched on a type plus a pseudo-class, so a single
 * class here is enough to outrank them wherever it matters.
 *
 * A button and not an <a href="#"> because the submenu opens on :focus-within
 * as well as :hover — an anchor without an href takes no focus, which would
 * leave the Company submenu unreachable by keyboard.
 */
.zouma-nav__list .zouma-nav__label {
  /* Reset the pill from style.css. */
  width: auto;
  background: none;
  border: 0;
  border-radius: 0;
  cursor: default;

  /* Then match .zouma-nav__list a exactly, so it is indistinguishable. */
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--zouma-transition);
}

/* Beats button:hover, which would otherwise repaint the pill on hover. */
.zouma-nav__list .zouma-nav__label:hover,
.zouma-nav__list li:hover > .zouma-nav__label {
  background: none;
  color: var(--zouma-cyan);
}

.zouma-nav__list .zouma-nav__label .zouma-icon--caret {
  color: var(--zouma-sky);
}

.zouma-nav__list li:hover > .zouma-nav__label .zouma-icon--caret {
  color: var(--zouma-cyan);
  transform: rotate(180deg);
}

.zouma-nav__list .sub-menu {
  position: absolute;
  top: calc(100% + 12px);
  left: 0;
  z-index: 10;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  min-width: 14rem;
  padding: 8px;
  background: var(--zouma-teal);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.35);
}

.zouma-nav__list .sub-menu a {
  padding: 8px 10px;
  border-radius: 4px;
}

.zouma-nav__list .sub-menu a:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}

/* Language switcher ------------------------------------------------------ */

.zouma-lang {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* 21px of text in a 60px bar: the box is grown to a tappable height rather
	 * than the label, so nothing about how it looks changes. */
  min-height: 40px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  cursor: pointer;
  transition: color var(--zouma-transition);
}

.zouma-lang:hover {
  background: transparent;
  color: var(--zouma-cyan);
  transform: none;
}

/* Header CTA ------------------------------------------------------------- */

/* Brand blue, not white. It is the only filled control in the bar and the bar
 * now floats over a dark hero, where a white button read as a second logo
 * rather than as the thing to press. */
.zouma-header__cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 16px;
  background: var(--zouma-blue);
  border: 0;
  border-radius: 4px;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background var(--zouma-transition),
    color var(--zouma-transition);
}

.zouma-header__cta:hover {
  background: var(--zouma-cyan);
  color: #fff;
  transform: none;
}

.zouma-header__cta .zouma-icon--arrow {
  transition: transform var(--zouma-transition);
}

.zouma-header__cta:hover .zouma-icon--arrow {
  transform: translateX(3px);
}

/* Mobile ----------------------------------------------------------------- */

@media (max-width: 1180px) {
  .zouma-nav {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    display: none;
    padding: 16px;
    background: var(--zouma-teal);
    border-radius: 8px;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.3);
  }

  .zouma-header__bar {
    position: relative;
  }

  .zouma-nav.is-open {
    display: block;
  }

  .zouma-nav__list,
  .zouma-nav__list .sub-menu {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }

  .zouma-nav__list .sub-menu {
    position: static;
    width: 100%;
    padding: 4px 0 0 14px;
    background: transparent;
    border: 0;
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .zouma-nav-toggle {
    display: inline-flex;
  }

  /* Touch targets.
	 *
	 * Measured on a phone, the menu links were 21px tall at the top level and
	 * 37px inside the submenus, and the hamburger 40px square. A fingertip
	 * needs 44px, so every one of them was a small target on the only widths
	 * where this menu is used at all. Nothing about the type, colour or order
	 * changes - only the box each link occupies, which is why the list gap
	 * above came off at the same time. */
  .zouma-nav__list a {
    display: flex;
    align-items: center;
    gap: 4px;
    min-height: 44px;
    width: 100%;
  }

  .zouma-nav-toggle,
  .zouma-lang {
    min-width: 44px;
    min-height: 44px;
  }

  .zouma-header__cta {
    min-height: 44px;
  }
}

@media (max-width: 620px) {
  .zouma-header__cta span {
    display: none;
  }

  /* Icon only at this width, which left the one control the page most
	 * wants tapped at 34x30. The bar is 60px tall and the actions row has
	 * 16px gaps, so there is room to make this comfortable for a thumb
	 * without moving anything around it or changing the header height. */
  .zouma-header__cta {
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 8px;
  }

  /* Shown here too. It used to be dropped below 620px on space grounds, which
	 * left a visitor who needs another language no way to switch on the width
	 * most of them are reading at - and no equivalent control anywhere else,
	 * since the switcher lives in the header bar rather than the nav panel.
	 * The label comes off instead: the globe carries the meaning, the button
	 * keeps its 44px target, and the row gets back the width the two letters
	 * were taking. */
  .zouma-lang span {
    display: none;
  }

  .zouma-lang {
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 8px;
  }
}

/* Header icon colours, sampled from the Figma vectors ---------------------
 * Globe and nav carets stroke #ADDBF3; the CTA arrow is #121212 on white.
 * The labels stay #FFFFFF, so the icons need their own colour rather than
 * inheriting from the text.
 */

.zouma-nav__list a .zouma-icon--caret,
.zouma-lang .zouma-icon--globe,
.zouma-lang .zouma-icon--caret {
  color: var(--zouma-sky);
}

.zouma-nav__list a:hover .zouma-icon--caret,
.zouma-nav__list li:hover > a .zouma-icon--caret,
.zouma-lang:hover .zouma-icon--globe,
.zouma-lang:hover .zouma-icon--caret {
  color: var(--zouma-cyan);
}

.zouma-lang span {
  color: #fff;
}

/* White, matching the label beside it. The arrow inherits currentColor, and it
 * was being pushed to the dark token — which read as a black mark sitting on
 * the blue fill while the text next to it stayed white. */
.zouma-header__cta .zouma-icon--arrow-right {
  color: #fff;
}

/* Sub-menu carets sit on the same dark surface. */
.zouma-nav__list .sub-menu .zouma-icon--caret {
  color: var(--zouma-sky);
}

/* The icon class is zouma-icon--arrow-right; keep the nudge on hover. */
.zouma-header__cta .zouma-icon--arrow-right {
  transition: transform var(--zouma-transition);
}

.zouma-header__cta:hover .zouma-icon--arrow-right {
  transform: translateX(3px);
}

/* =========================================================================
 * 01 · Hero — rebuilt from the Figma frame.
 *
 *   H1        Albert Sans 700 · 57/60 · #121212 · max 670px
 *   Sub       Poppins 500 · 16/29 · #121212
 *   Buttons   16/600 Poppins · 4px radius · 8/16 padding · 16px gap
 *   Trust     Poppins 400 · 16/26 · logos 92×20, 40px gaps, 2 rows
 *   Info bar  full-bleed · 53px · 1px #e4e9ee rules · 64px gaps
 *             14/500 Poppins · 11px #5fc0ea dot
 * ====================================================================== */

.zouma-hero {
  position: relative;
  isolation: isolate;
  /* A full screen, on any device.
	 *
	 * min-height, never height: if the copy, the CTAs, the logo rail and the
	 * info bar together need more room than the screen has — a short laptop in
	 * landscape, a phone with large type — the section grows instead of
	 * clipping them.
	 *
	 * svh after vh: 100vh on a phone measures the viewport with the browser
	 * chrome retracted, so a section sized to it runs taller than what is
	 * actually visible and the info bar sits below the fold. svh is what the
	 * visitor can see. vh stays first as the fallback. */
  min-height: 100vh;
  min-height: 100svh;
  /* The section starts under the sticky header, so the negative margin above
	 * is already counted in that 100 — no need to subtract the header again. */
  display: flex;
  flex-direction: column;
  margin-top: calc(-1 * var(--zouma-header-h));
  padding-top: calc(
    var(--zouma-header-h) + clamp(3rem, calc(6 * var(--zouma-vw)), 6.5rem)
  );
  background: #0d0d0d;
  overflow: hidden;
  text-align: center;
}

.zouma-hero--left {
  text-align: left;
}

.zouma-hero--left .zouma-hero__title,
.zouma-hero--left .zouma-hero__sub {
  margin-inline: 0;
}

.zouma-hero--left .zouma-hero__ctas,
.zouma-hero--left .zouma-hero__logos {
  justify-content: flex-start;
}

/* Background ------------------------------------------------------------- */

.zouma-hero__bg {
  position: absolute;
  inset: 0 0 53px;
  z-index: -1;
  pointer-events: none;
}

.zouma-hero__image {
  position: absolute;
  inset: 0;
  background-position: center bottom;
  background-repeat: no-repeat;
  background-size: cover;
  opacity: 0.3;
}

/* Scrim behind the copy.
 *
 * The artwork carries a lit wave crest straight through the middle of the
 * section, which is exactly where the sub-heading and the second button sit —
 * white text on a pale ridge, at about 2:1. This puts the contrast back.
 *
 * Shaped rather than a flat wash: an ellipse over the text block only, so the
 * crest still reads at the edges of the frame and the picture keeps its
 * contrast everywhere the copy is not. */
.zouma-hero__image::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse 48% 40% at 50% 36%,
    rgba(4, 8, 12, 0.66) 0%,
    rgba(4, 8, 12, 0.38) 54%,
    rgba(4, 8, 12, 0) 100%
  );
  pointer-events: none;
}

/* 6px dots on a ~30px grid, #ADDBF3. */
.zouma-hero__dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(
    circle,
    var(--zouma-sky) 2.6px,
    transparent 2.8px
  );
  background-size: 30.5px 29.5px;
  opacity: 0.55;
}

/* Four blurred colour fields; opacity and hue taken from the Figma layers. */
.zouma-hero__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(115px);
}

.zouma-hero__blob--1 {
  top: 13%;
  left: 6%;
  width: 40%;
  height: 40%;
  background: #93d2f0;
  opacity: 0.55;
}

.zouma-hero__blob--2 {
  top: 42%;
  left: 24%;
  width: 45%;
  height: 37%;
  background: var(--zouma-sky-soft);
  opacity: 0.5;
}

.zouma-hero__blob--3 {
  top: 18%;
  left: 46%;
  width: 37%;
  height: 34%;
  background: var(--zouma-blue);
  opacity: 0.4;
}

.zouma-hero__blob--4 {
  top: 43%;
  left: 61%;
  width: 32%;
  height: 31%;
  background: #45b7e7;
  opacity: 0.4;
}

/* The four pale blobs belong to the light hero and have no part in this one.
 * The reference carries exactly one source of colour — the cyan rising off the
 * bottom edge — and blurred fields sitting over the wave crests grey them out,
 * which is the one thing the surface cannot afford. Hidden rather than deleted
 * so a light hero still has its layers. */
.zouma-hero .zouma-hero__blob {
  display: none;
}

/* The data grid. Centred behind the hero copy, dark blue-grey and barely
 * there — a technological texture, not a starfield. The original was 2.6px
 * sky blue full-bleed, which on black was a hard dot grid over everything. */
.zouma-hero .zouma-hero__dots {
  background-image: radial-gradient(
    circle,
    rgba(122, 146, 168, 0.5) 1.1px,
    transparent 1.3px
  );
  background-size: 26px 26px;
  opacity: 0.16;
  -webkit-mask-image: radial-gradient(
    ellipse 40% 40% at 45% 40%,
    #000 0%,
    transparent 74%
  );
  mask-image: radial-gradient(
    ellipse 40% 40% at 45% 40%,
    #000 0%,
    transparent 74%
  );
}

/* The contour field.
 *
 * A flat SVG rather than the canvas animation that used to sit here. The
 * design's background does not move, and an animated field behind a headline
 * costs a canvas, a requestAnimationFrame loop and a module download to render
 * something the reader is not meant to look at. This is one cacheable vector
 * with no script behind it, and it cannot drop frames on a slow machine.
 *
 * "slice" on the SVG's own preserveAspectRatio plus cover here means the field
 * fills the hero at any shape without the curves ever stretching. */
/* The wave field. Still — no drift, no parallax, no pointer lean. */
.zouma-hero__waves {
  position: absolute;
  inset: 0;
  background: url("../images/hero-waves.svg") center center / cover no-repeat;
  pointer-events: none;
}

/* Radial white vignette that fades the whole field into the page.
 *
 * Pulled back from what the colour fields needed. At its old strength it had
 * washed the tiles to flat white across the outer third, so the grid only ever
 * read in the middle of the section — it now holds the very edges and lets the
 * surface carry the rest. */
/* The one source of colour in the frame, and the vignette under it.
 *
 * Layer order matters here: in the shorthand the first layer paints on top, so
 * the cyan sits over the vignette. The other way round the vignette would grey
 * the glow off at exactly the point it is meant to be brightest.
 *
 * The glow is tight and sits off-centre on the bottom edge, not centred and
 * wide — in the reference it reads as light coming from a source just out of
 * frame, and a symmetrical wash across the whole foot reads as a gradient
 * instead. */
.zouma-hero__veil {
  position: absolute;
  inset: 0;
  background:
		/* #00AEEF, held well back. It should read as light falling on the wave
		 * surfaces rather than as a blue gradient laid over them, so it is wide
		 * and weak instead of tight and saturated. */
    radial-gradient(
      ellipse 30% 26% at 48% 102%,
      rgba(0, 174, 239, 0.3) 0%,
      rgba(0, 159, 227, 0.11) 44%,
      rgba(0, 140, 200, 0) 78%
    ),
    /* Only the very corners. At its previous strength this reached three
		 * quarters of the way in and flattened the wave field to near-black
		 * everywhere but the middle — the artwork was doing its job and the
		 * vignette was hiding it. */
    radial-gradient(
        ellipse 92% 88% at 50% 46%,
        rgba(10, 10, 10, 0) 0%,
        rgba(10, 10, 10, 0.18) 82%,
        rgba(10, 10, 10, 0.55) 100%
      );
}

/* Cursor-reactive backdrop ------------------------------------------------ */

/* Sits above .zouma-hero__bg (z-index -1) and below the copy, so the section
 * reads as one surface rather than a canvas pasted over a picture.
 *
 * pointer-events is the load-bearing line. The plane tracks the cursor off the
 * window, never off itself, so taking events here would do nothing but swallow
 * the clicks meant for the two buttons and the logo rail sitting on top. */
.zouma-hero__glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* The artwork in .zouma-hero__image is the background. This canvas is only
	 * the light on top of it.
	 *
	 * Left alone the plane is opaque — its shader paints its own near-black
	 * ground — so it hid the artwork completely. Screen throws that ground away
	 * instead: black contributes nothing, and only the cyan and white the
	 * shader draws survive to land on the picture. */
  mix-blend-mode: screen;
  /* Held well back. The shader draws a glow meant to be the whole background,
	 * and the artwork underneath already has one — screened at full strength
	 * the two stack into a flat white band that swallows the logo rail. At this
	 * weight the picture stays the picture and the plane is just the live light
	 * moving over it. */
  opacity: 0.58;
  /* Confined to the foot, where the artwork's own glow already is. Screening
	 * the shader's 0.08 ground over the whole hero would lift every black in
	 * the picture to a flat grey; down here the surface is bright enough that
	 * the same lift reads as the glow it is meant to be. */
  -webkit-mask-image: linear-gradient(
    to top,
    #000 0%,
    #000 18%,
    transparent 62%
  );
  mask-image: linear-gradient(to top, #000 0%, #000 18%, transparent 62%);
}

/* Content ---------------------------------------------------------------- */

/* Takes the slack. The section is a column of two children — this and the info
 * bar — so growing only this one keeps the bar pinned to the bottom edge of the
 * screen while the copy stays centred in whatever is left above it. */
.zouma-hero__inner {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-bottom: clamp(2.5rem, calc(5 * var(--zouma-vw)), 4rem);
}

.zouma-hero__title {
  max-width: 670px;
  margin: 0 auto;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(2.25rem, 1.05rem + calc(3.6 * var(--zouma-vw)), 3.5625rem);
  font-weight: 700;
  line-height: 1.053;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.zouma-hero__sub {
  max-width: 670px;
  margin: 24px auto 0;
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--zouma-font-body);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.8125;
}

/* The pair reads primary-then-secondary on the dark ground: brand blue for the
 * action, a glass outline for the alternative. Scoped to the hero rather than
 * changed on the shared --dark/--white variants, which still sit on light
 * sections everywhere else on the site. */
.zouma-hero__ctas .zouma-btn--dark {
  background: var(--zouma-blue);
  border-color: var(--zouma-blue);
  color: #fff;
}

.zouma-hero__ctas .zouma-btn--dark:hover {
  background: var(--zouma-cyan);
  border-color: var(--zouma-cyan);
  color: #fff;
}

/* Solid, not glass.
 *
 * This was a 6% white wash over a 28% white hairline — a ghost button that read
 * as an outline on the dark hero and all but vanished over the lighter part of
 * the background image. The design has it as a filled white button beside the
 * dark one, so it is filled: white ground, dark label, and the arrow follows on
 * currentColor.
 *
 * Scoped to .zouma-hero__ctas, which only the homepage hero uses — the plain
 * .zouma-btn--white on Case Studies is untouched and was already solid.
 */
.zouma-hero__ctas .zouma-btn--white {
    background: #fff;
    border-color: #fff;
    color: var(--zouma-dark);
  }

  /* Tints rather than lifts: on white there is no brighter state to go to, so
   * the hover steps toward the brand's pale blue instead. */
  .zouma-hero__ctas .zouma-btn--white:hover {
    background: var(--zouma-blue-pale);
    border-color: var(--zouma-blue-pale);
    color: var(--zouma-dark);
  }

.zouma-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin-top: 24px;
}

/* Buttons ---------------------------------------------------------------- */

.zouma-btn--dark,
.zouma-btn--white {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 4px;
  font-family: var(--zouma-font-body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.625;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background var(--zouma-transition),
    color var(--zouma-transition),
    border-color var(--zouma-transition);
}

.zouma-btn--dark {
  background: var(--zouma-dark);
  color: #fff;
  border: 1px solid var(--zouma-dark);
}

.zouma-btn--dark:hover {
  background: var(--zouma-teal);
  border-color: var(--zouma-teal);
  color: #fff;
  transform: none;
}

.zouma-btn--white {
  background: #fff;
  color: var(--zouma-dark);
  border: 1px solid #e4e9ee;
}

.zouma-btn--white:hover {
  background: var(--zouma-blue-pale);
  border-color: var(--zouma-sky);
  color: var(--zouma-dark);
  transform: none;
}

.zouma-btn--dark .zouma-icon,
.zouma-btn--white .zouma-icon {
  transition: transform var(--zouma-transition);
}

.zouma-btn--dark:hover .zouma-icon,
.zouma-btn--white:hover .zouma-icon {
  transform: translateX(3px);
}

/* Trust strip ------------------------------------------------------------ */

.zouma-hero__trust {
  margin-top: clamp(2.5rem, calc(5 * var(--zouma-vw)), 6.5rem);
}

.zouma-hero__trust-title {
  margin: 0;
  color: rgba(255, 255, 255, 0.88);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.625;
}

.zouma-hero__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 40px;
  max-width: 970px;
  margin: 40px auto 0;
  padding: 0;
  list-style: none;
}

.zouma-hero__logos li {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 92px;
  height: 20px;
}

/* No hover state — see the note on the Book a Call trust row. The rail is one
 * piece of texture; picking single marks out of it on hover reads as though
 * they were clickable.
 *
 * On the dark hero the marks have to be knocked out to white rather than just
 * desaturated: these files are dark artwork drawn for a light page, and
 * grayscale alone leaves them near-invisible here. brightness(0) flattens each
 * one to solid black whatever its colours were, and invert(1) lifts that to
 * white — so every logo lands at the same weight regardless of what it started
 * as. The Book a Call wall sits on white and keeps the plain grey treatment. */
.zouma-hero__logos img {
  max-width: 100%;
  max-height: 20px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: brightness(0) invert(1);
  /* Matches the vectors below. The two used to differ — 0.72 against 0.9 —
	 * because the vectors were pale sky and the knocked-out rasters were pure
	 * white, and holding the rasters back was what stopped them shouting over
	 * the colour. Now that every mark is white, the same two numbers read as
	 * one row of logos lit at two different strengths. */
  opacity: 0.9;
}

/* Vector logos are already white for this ground, so they are left alone.
 * Knocking them out would gain nothing and, on the ones carrying counters —
 * LG's roundel, the dot in Eco — it would flatten the dark cut-outs into the
 * light shape and leave a solid blob. */
.zouma-hero__logos img.is-vector {
  filter: none;
  opacity: 0.9;
}

/* Info bar --------------------------------------------------------------- */

/* Sits at the foot of the dark hero, so it is a shade lifted off it rather
 * than a white strip cutting the section in two. */
.zouma-infobar {
  position: relative;
  background: rgba(255, 255, 255, 0.03);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.zouma-infobar__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px 64px;
  min-height: 53px;
  margin: 0;
  padding: 8px clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
  list-style: none;
}

.zouma-infobar__item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: rgba(255, 255, 255, 0.88);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}

.zouma-infobar__item img {
  width: 16px;
  height: 16px;
  object-fit: contain;
}

/* A plain bullet on this bar, not the mark.
 *
 * The row is five short claims read as a list, and at 14px type the mark was
 * competing with the words it introduces. A dot separates them without asking
 * to be looked at. Sized against that type rather than left at the mark's box,
 * so the item gap below is widened to suit. */
.zouma-infobar__dot {
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  background: var(--zouma-cyan-soft);
  border-radius: 50%;
}

@media (max-width: 900px) {
  .zouma-infobar__list {
    gap: 10px 28px;
  }

  .zouma-hero__logos {
    gap: 28px;
  }
}

@media (max-width: 560px) {
  .zouma-hero__ctas .zouma-btn--dark,
  .zouma-hero__ctas .zouma-btn--white {
    justify-content: center;
    width: 100%;
  }
}

/* The design title-cases button and info-bar labels via a transform rather
 * than in the copy ("Start a Conversation" renders as "Start A Conversation").
 * Keeping it in CSS means the admin copy stays natural to read and edit. */
.zouma-btn--dark span,
.zouma-btn--white span,
.zouma-infobar__item span {
  text-transform: capitalize;
}

/* Logo strip: two explicit rows (8 + 7), matching the Figma layout, rather
 * than a single flow that wraps wherever the width runs out. */
.zouma-hero__logos {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  max-width: none;
  margin: 40px auto 0;
  padding: 0;
  list-style: none;
}

.zouma-hero__logo-row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: 40px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zouma-hero__logo-row li {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 1 92px;
  height: 20px;
}

.zouma-hero__logo-row img {
  max-width: 100%;
  max-height: 20px;
  width: auto;
  object-fit: contain;
}

/* Below the point where a full row would squash, allow wrapping again. */
@media (max-width: 1080px) {
  .zouma-hero__logos {
    gap: 28px;
  }

  .zouma-hero__logo-row {
    flex-wrap: wrap;
    gap: 24px 32px;
  }
}

/* Marquee — the two rows travelling against each other.
 *
 * Only in force once hero-motion.js has cloned each row's logos and can drive
 * them; without JavaScript, or under reduced motion, none of this matches and
 * the strip is the centred pair of rows it has always been.
 *
 * The wrap above has to go: a marquee is one line by definition, and a row that
 * wrapped would be scrolling several stacked lines at once. Alignment goes to
 * the start for the same reason the overflow is hidden here — a centred row
 * wider than its box starts at a negative offset, and the transform needs to
 * count from the box's own left edge. */
.zouma-hero__logos.is-marquee {
  align-items: flex-start;
  overflow: hidden;
}

.zouma-hero__logos.is-marquee .zouma-hero__logo-row {
  flex-wrap: nowrap;
  justify-content: flex-start;
  width: max-content;
  will-change: transform;
}

/* =========================================================================
 * 02 · Who is Zouma — photo left, copy right, trust rail underneath.
 *
 * Replaces the pinned intro statement that used to sit here. That statement
 * held a full screen to itself and darkened a word at a time as you scrolled;
 * this band says the same thing at a glance, so it is a plain flow section —
 * no pinning, no scroll track, and no JavaScript behind it.
 *
 * The trust rail below is unchanged and still reads the hero_logos rows, so
 * the brand set is edited in one place exactly as before.
 * ====================================================================== */

.zouma-whois {
  /* Height comes from the content, not the viewport.
	 *
	 * min-height: auto rather than simply deleting the declaration: the shared
	 * `main > section` rule at the foot of this file floors every band at
	 * 100svh, so dropping it here would hand the section straight back to that
	 * floor. A class outranks that (0,0,2) selector, so the opt-out has to be
	 * stated rather than implied — the same way .zouma-stats and
	 * .zouma-careers do it.
	 *
	 * align-content: space-between below is kept but now has no spare height
	 * to hand out, which is the point: the trust rail sits directly under the
	 * copy rather than being pushed down to a screen-bottom. */
  min-height: auto;
  padding-block: clamp(4.5rem, calc(9 * var(--zouma-vw)), 7.5rem);

  /* space-between, not the centre this inherits from `main > section`.
	 *
	 * The section has exactly two rows — the copy-and-photo shell, and the
	 * trust block that carries the "Trusted by" line together with its logo
	 * rail. Centring held them as one group in the middle of the viewport and
	 * split the spare height above and below, which left the rail floating.
	 * space-between puts the first row at the top and the last at the bottom
	 * and gives all the spare height to the gap between them, so the rail sits
	 * on the section's floor at any viewport height.
	 *
	 * The two stay a single block because they already are one: the heading and
	 * the cards are both inside .zouma-trust, so nothing can come between
	 * them. */
  align-content: space-between;

  /* Both edges take the padding-block above.
	 *
	 * The foot used to be zeroed, so the logo rail finished hard against the
	 * band's bottom edge while the top carried a full 120px — the section read
	 * as top-heavy and the rail as cut off. The marquee window still holds its
	 * own 5px under the cards, which is what the old rule was avoiding
	 * doubling up; against a 120px foot that is a rounding error, not a
	 * stacked gap. */

  /* The 8px separating this band from the next.
	 *
	 * Margin, not padding. Padding would sit inside the band, under its own
	 * background, so there would be nothing to see between the two sections.
	 * A bottom margin is outside the border box, so the gap reads as a gap
	 * and the next section starts 8px later.
	 *
	 * Flat px, not a clamp — the same 8px on a phone and on a wide
	 * monitor. */
  margin-bottom: 8px;
  /* Near-white, where this band used to be the #E1EDF9 panel. The design
	 * lightens it so the photo and the logo marks carry the colour. */
  background-color: #f7fafc;
  /* The dot field the old stage carried, kept to a whisper. Same 28px pitch,
	 * so the band still belongs to the same family as the rest of the page. */
  background-image: radial-gradient(
    circle,
    rgba(11, 74, 108, 0.07) 1.5px,
    transparent 1.5px
  );
  background-size: 28px 28px;
}

/* Two equal columns across the full shell. */
.zouma-whois__grid {
  display: grid;
  /* minmax(0, 1fr), not 1fr: a grid column defaults to a min-content floor,
	 * and the photo would hold the left column open at its intrinsic width. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* Stretch, so the photo column has a height to fill. The copy re-centres
	 * itself inside it with align-self. */
  align-items: stretch;
  /* 66px between the photograph and the copy at design width, which is
	 * what the reference measures; 52px sat the two columns too close. */
  gap: clamp(1.75rem, calc(4.6 * var(--zouma-vw)), 4.125rem);
}

/* The photo box.
 *
 * No aspect-ratio here, deliberately. Pairing aspect-ratio with a min-height
 * makes the browser transfer that minimum through the ratio into a minimum
 * *width* as well — 34rem tall at 356/246 demands 787px wide — and on a large
 * screen the figure then outgrew its grid column, spilled past the shell and
 * ran underneath the paragraph. Height alone sizes the box now; object-fit:
 * cover on the image absorbs whatever shape the column ends up being, which
 * is what it was there for in the first place.
 *
 * min-width: 0 and max-width: 100% are the belt and braces: a grid item's
 * default min-width is auto, which refuses to shrink below its content, and
 * the content here is a 1200px-wide photo. */
.zouma-whois__figure {
  margin: 0;
  min-width: 0;
  max-width: 100%;
  /* A fixed proportion, not a share of the viewport height.
	 *
	 * This was height: 100% over a min-height of 46vh, so the photo's shape
	 * followed the window: 460px tall at a 1000px viewport against 594 wide,
	 * a 1.29 crop where the design draws 1.45. Taller windows made it squarer
	 * still. An aspect-ratio pins the shape to the column width instead, so it
	 * matches the design at every window height.
	 *
	 * align-self overrides the grid's stretch — without it the row height wins
	 * and the ratio never gets to apply. min-height: 0 for the same reason it
	 * is on .zouma-towcard__media: an aspect-ratio under a min-height resolves
	 * into a minimum *width*, which would push the column open.
	 */
  align-self: center;
  aspect-ratio: 1.45;
  min-height: 0;
  overflow: hidden;
  border-radius: 14px;
}

.zouma-whois__figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.zouma-whois__copy {
  /* The column stretches so the photo beside it can; the copy itself sits
	 * in the middle of that height rather than being pulled to the top. */
  align-self: center;
  min-width: 0;
}

.zouma-whois__title {
  margin: clamp(0.75rem, calc(1.4 * var(--zouma-vw)), 1.125rem) 0 0;
  color: #16202e;
  font-family: var(--zouma-font-heading);
  font-size: var(--zouma-size-h2);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-whois__text {
  margin: clamp(0.875rem, calc(1.6 * var(--zouma-vw)), 1.25rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: var(--zouma-size-body);
  font-weight: 400;
  line-height: 1.75;
}

/* One column once the two get too narrow to hold a photo and a paragraph side
 * by side. 900px is where the rest of the page's two-column bands stack, so
 * this one turns at the same point rather than inventing its own.
 *
 * The photo is already first in the source, so the stack needs no reordering
 * and the reading order stays correct. Its height comes down at the same time:
 * at 46vh the photo would take nearly half a phone screen and push the
 * paragraph below the fold, which is the one thing this band cannot afford —
 * the whole point of it is that both are read together. */
@media (max-width: 900px) {
  .zouma-whois__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-whois__figure {
    min-height: clamp(13rem, 34vh, 20rem);
  }
}

/* Small phone. The band takes its content's height here as it does at every
 * width — it no longer holds a screen floor. The photo still gives back more
 * of the screen so the paragraph is not pushed under the fold, and the
 * padding comes in with it. */
@media (max-width: 620px) {
  .zouma-whois {
    padding-block: clamp(3rem, calc(8 * var(--zouma-vw)), 4.5rem);
    /* Restated: the padding-block above resets both edges, and this query
		 * sits after the rule that clears the foot. */
    padding-bottom: 0;
  }

  .zouma-whois__figure {
    min-height: clamp(11rem, 30vh, 16rem);
  }
}
/* Trust rail, on the pale panel ------------------------------------------ */

/* Well clear of the copy above. The two are separate thoughts and the band is
 * short enough that a tight gap makes the logos read as a footnote to the
 * paragraph rather than as their own strip. */
.zouma-trust {
  /* Card metrics. The design reference measures 238x113 with an 18px gap at
	 * the full 1440 layout; these run well under that, at 162x77 with a 14px
	 * gap, because the reference size read too heavy on the page.
	 *
	 * --zouma-vw is capped at 14.4px, so the calc arms land exactly on those
	 * figures at design width and scale down from there. The clamp floors stop
	 * the cards collapsing on a phone, where a card much narrower than 104px
	 * can no longer hold a wordmark.
	 *
	 * The logos inside are capped as a share of the card, so they follow this
	 * change on their own and keep their proportions. Card size does drive the
	 * marquee speed, though — see the duration note below. */
  --zouma-trust-card-w: clamp(104px, calc(11.25 * var(--zouma-vw)), 162px);
  --zouma-trust-card-h: clamp(50px, calc(5.35 * var(--zouma-vw)), 77px);
  --zouma-trust-gap: clamp(8px, calc(0.97 * var(--zouma-vw)), 14px);

  justify-self: stretch;
  width: 100%;
  /* The load-bearing line. A grid item defaults to min-width: auto, which
	 * refuses to shrink below its content's min-content width — and this
	 * content is a marquee track that never wraps, so that floor is the full
	 * 3295px of both logo copies. width: 100% loses to it and the "window"
	 * ends up as wide as the thing it is supposed to be clipping. */
  min-width: 0;
  margin-top: clamp(3.5rem, calc(7 * var(--zouma-vw)), 6.5rem);
}

.zouma-trust__title {
  margin: 0 0 clamp(1.25rem, calc(2.6 * var(--zouma-vw)), 2rem);
  color: #7c8996;
  font-family: var(--zouma-font-body);
  /* Tracked-out capitals, as the design sets this line. It was reading as
	 * a sentence in title case at 14px, which made it compete with the copy
	 * above rather than labelling the rail below it. */
  font-size: clamp(0.6875rem, 0.65rem + calc(0.16 * var(--zouma-vw)), 0.75rem);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
}

/* The window the strip moves behind. Edge to edge, and clipping — without the
 * hidden overflow the second copy of the list would widen the page. */
.zouma-trust__viewport {
  /* 32px of clearance under the cards.
	 *
	 * This window is exactly as tall as a card and clips with overflow: hidden,
	 * so without it the cards' bottom edge sits on the cut and reads as
	 * touching the floor of the rail. Padding moves the cut down without
	 * changing the cards themselves.
	 *
	 * It is the whole gap: the section carries no foot of its own, so this is
	 * the distance from the cards to the section's bottom edge. 5px measured
	 * correctly but did not read as a gap — the band, the gap and the section
	 * below it are all within a few RGB points of each other, so there is no
	 * visible boundary for a hairline of space to sit against. */
  padding-bottom: 32px;
  overflow: hidden;
  /* Fades the marks out into the panel at both ends instead of cutting them
	 * off mid-logo against a hard edge. */
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0,
    #000 6%,
    #000 94%,
    transparent 100%
  );
  mask-image: linear-gradient(
    90deg,
    transparent 0,
    #000 6%,
    #000 94%,
    transparent 100%
  );
}

/* Two copies of the list side by side, shifted by exactly half their combined
 * width. At -50% the second copy sits precisely where the first started, so
 * the loop point is invisible and there is no jump to hide. */
.zouma-trust__track {
  display: flex;
  width: max-content;
  /* 94s, tracking the card size.
	 *
	 * The duration is fixed but the distance is not: the animation travels
	 * -50% of the track, so the speed on screen is set by how wide the track
	 * happens to be. Boxing each mark in a 238px card widened one copy of the
	 * row from roughly 1650px to 3000px, which at the original 52s would have
	 * scrolled the strip more than twice as fast as it did before — a visible
	 * change nobody asked for. Scaling the duration by the same factor holds
	 * the strip at its original ~32px/s.
	 *
	 * Recompute this whenever the card metrics move: one copy of the row is
	 * 17 x (card-w + gap), and the duration wanted is that over 32. */
  animation: zouma-trust-scroll 94s linear infinite;
}

@keyframes zouma-trust-scroll {
  to {
    transform: translateX(-50%);
  }
}

/* Nothing wraps — a marquee row is a single line by definition. */
.zouma-trust__row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  /* The gap and the trailing padding must stay identical. The marquee is two
	 * copies of this row shifted by exactly -50%, so the space after the last
	 * card has to equal the space between cards or the loop shows a seam every
	 * time it wraps. Change one, change the other. */
  gap: var(--zouma-trust-gap);
  margin: 0;
  padding: 0;
  padding-inline-end: var(--zouma-trust-gap);
  list-style: none;
}

/* Stopped for anyone who asks for less motion — the strip is still there and
 * still readable, it simply does not move. */
@media (prefers-reduced-motion: reduce) {
  .zouma-trust__track {
    animation: none;
  }
}

/* Each mark sits in its own card, as in the design: a hairline rule, a soft
 * radius, and a fill that is white but not opaque — the band's dot field
 * still reads faintly through it in the reference, so a solid white would
 * punch a hole in the pattern rather than sit on it.
 *
 * flex-shrink: 0 because the row is a marquee: it is wider than the screen
 * by design, and without this the cards would compress to fit instead of
 * overflowing and scrolling. */
.zouma-trust__row li {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--zouma-trust-card-w);
  height: var(--zouma-trust-card-h);
  padding: 0 clamp(0.75rem, calc(1.4 * var(--zouma-vw)), 1.25rem);
  /* The fill is lifted along with the border. At 0.62 the card was barely
	 * distinct from the band behind it, which left the rule doing all the work
	 * of describing the card; a touch more white gives the border something to
	 * edge, and the dot field still reads through as it does in the design. */
  background: rgba(255, 255, 255, 0.72);
  /* Specified by the client. Eight-digit hex: the theme's own muted ink,
	 * #5B6770, carried at 33 alpha — 20%. Because it is translucent rather
	 * than a flat tint, the edge picks up whatever it happens to sit over,
	 * so it stays consistent where a card crosses the band's dot field. */
  border: 1px solid #5b677033;
  border-radius: 10px;
}

/* Capped as a share of the card rather than at a fixed height.
 *
 * The old flat max-height forced every mark to exactly 17px tall, which
 * normalised them all to one height. The design does not do that — a wide
 * wordmark like Jakson sits short and broad, a stacked mark like Green Eco
 * stands tall — because the binding limit differs per logo. Two percentage
 * caps reproduce that: wide artwork meets the width cap first, tall artwork
 * meets the height cap, and each keeps its own proportions.
 *
 * width/height auto with object-fit: contain means nothing is ever stretched
 * — the caps only ever scale a mark down, never distort it. */
.zouma-trust__row img {
  max-width: 68%;
  max-height: 60%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* brightness(0) rather than grayscale(1).
 *
 * Desaturating only removes colour — it leaves a pale mark pale, and several
 * of these files are light grey artwork. Lemmorte, Aspire and Incorporatewear
 * came out almost invisible on the panel while their neighbours read fine.
 * Flattening every mark to black first and setting the weight with opacity
 * puts them all at the same strength whatever they started as. */
.zouma-trust__row img {
  filter: brightness(0);
  opacity: 0.58;
}

/* The vectors are the opposite problem. They were recoloured white for the
 * dark hero, and white on a pale panel is nothing at all, so they have to be
 * turned around: grayscale flattens each to white, invert drops it to a dark
 * grey that sits at the same weight as the rasters beside it. */
.zouma-trust__row img.is-vector {
  filter: grayscale(1) invert(1);
  opacity: 0.62;
}

/* The pass above does not reach a fine-lined mark that only ships as a 92x20
 * raster: most of it survives the downscale as part-transparent anti-aliasing,
 * so on the plate it measured a mean luminance of 240 where hazelmont, the
 * strongest raster here, sits at 226.
 *
 * Opacity is not enough on its own - taken all the way to 1 the mark this was
 * written for only reached 231, because what it is short of is coverage rather
 * than darkness. A single hairline shadow puts back the alpha the downscale
 * ate and brings it to 228, level with its neighbours. Two shadows overshoot
 * and start to read as a bolder logo than the brand's own.
 *
 * Nothing carries this class as it stands - incorporatewear, the one mark that
 * did, is now a vector and zouma_faint_logos() is empty. Kept as the other
 * half of that list, which is where the next thin raster lands. */
.zouma-trust__row img.is-faint-art {
  filter: brightness(0) drop-shadow(0 0 0.35px rgba(0, 0, 0, 1));
  opacity: 0.85;
}

/* =========================================================================
 * 03 · Stats grid — from the Figma "Section / Outcomes" frame.
 *
 *   Eyebrow  20px mark + Poppins 12/600, 0.08em tracking, #121212
 *   Title    Albert Sans 700 · 30/39 · 870px, centred
 *   Cells    326×141 · 24/40 padding · 8px gap
 *   Value    Albert Sans 700 · 32/35 · #0E85B6
 *   Label    Poppins 500 · 16/29 · #121212
 *   Detail   Poppins 500 · 12/17 · #5B6770
 *   Rules    2px #C7E4F6, fading over the 96/80px overhang
 *   Nodes    6px #5FC0EA dots at every intersection
 * ====================================================================== */

.zouma-stats {
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 7.5rem);
  background: #fff;
}

.zouma-stats__head {
  margin-bottom: 40px;
  text-align: center;
}

.zouma-stats .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 16px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-stats .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-stats__title {
  max-width: 870px;
  margin: 0 auto;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
  text-align: center;
}

/* Frame: the grid box, with the rules overhanging it on every side. */
.zouma-statgrid__frame {
  /* Overhang values live on .zouma-stats so the head spacing can use them. */
  --zouma-rule: #c7e4f6;

  position: relative;
  max-width: 978px;
  margin: 0 auto;
}

.zouma-statgrid__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(var(--zouma-cols, 3), minmax(0, 1fr));
}

.zouma-statgrid__cell {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 24px 40px;
  text-align: center;
}

.zouma-statgrid__value {
  margin: 0;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.09;
  letter-spacing: 0;
}

/* "24x6" sets the separator smaller than the figures. */
.zouma-statgrid__value span {
  font-size: 0.7em;
}

.zouma-statgrid__label {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 1rem;
  font-weight: 500;
  /* 1.8125 was set for the single-line labels and read as a gap once one of
   * them wrapped — "Workflows Automated" sat 29px apart on 16px type. This is
   * ordinary label leading: closer, without the two lines touching. */
  line-height: 1.4;
}

.zouma-statgrid__text {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.4167;
}

/* Decorative rules ------------------------------------------------------- */

.zouma-statgrid__rules {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.zouma-statgrid__vline,
.zouma-statgrid__hline {
  position: absolute;
}

/* Verticals sit on each column boundary and run past the grid vertically,
 * fading out across the overhang. */
.zouma-statgrid__vline {
  top: calc(var(--zouma-overhang-y) * -1);
  bottom: calc(var(--zouma-overhang-y) * -1);
  left: calc(var(--i) / var(--zouma-cols) * 100%);
  width: 2px;
  margin-left: -1px;
  background: linear-gradient(
    180deg,
    transparent 0,
    var(--zouma-rule) var(--zouma-overhang-y),
    var(--zouma-rule) calc(100% - var(--zouma-overhang-y)),
    transparent 100%
  );
}

/* Horizontals sit on each row boundary and run past the grid horizontally. */
.zouma-statgrid__hline {
  left: calc(var(--zouma-overhang-x) * -1);
  right: calc(var(--zouma-overhang-x) * -1);
  top: calc(var(--i) / var(--zouma-rows) * 100%);
  height: 2px;
  margin-top: -1px;
  background: linear-gradient(
    90deg,
    transparent 0,
    var(--zouma-rule) var(--zouma-overhang-x),
    var(--zouma-rule) calc(100% - var(--zouma-overhang-x)),
    transparent 100%
  );
}

.zouma-statgrid__dot {
  position: absolute;
  left: calc(var(--x) / var(--zouma-cols) * 100%);
  top: calc(var(--y) / var(--zouma-rows) * 100%);
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--zouma-cyan-soft);
  border-radius: 50%;
}

@media (max-width: 820px) {
  .zouma-statgrid__frame {
    --zouma-cols: 2;
    --zouma-overhang-x: 40px;
    --zouma-overhang-y: 40px;
  }

  .zouma-statgrid__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .zouma-statgrid__cell {
    padding: 20px 16px;
  }

  /* Rules are drawn for the desktop column count; hide them once the grid
	 * reflows rather than showing lines that no longer align. */
  .zouma-statgrid__rules {
    display: none;
  }

  .zouma-statgrid__cell {
    border-bottom: 1px solid var(--zouma-rule);
  }
}

@media (max-width: 520px) {
  /* The count is what the grid is actually built from, and what the reveal
	 * reads back — the frame is not a grid, so setting columns on it did
	 * nothing. */
  .zouma-statgrid__frame {
    --zouma-cols: 1;
  }

  .zouma-statgrid__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Spacing correction: Figma puts 40px between the title block and the top of
 * the grid frame, and the frame opens with an 80px empty row before the first
 * rule. The rules layer is drawn from the cell box outwards, so the head needs
 * to clear the overhang as well as the 40px gap. */
.zouma-stats {
  --zouma-overhang-x: 96px;
  --zouma-overhang-y: 80px;
  --zouma-head-gap: 40px;
}

.zouma-stats__head {
  margin-bottom: calc(var(--zouma-head-gap) + var(--zouma-overhang-y));
}

.zouma-statgrid__frame {
  /* Reserve room for the rules that extend below the last row. */
  margin-bottom: var(--zouma-overhang-y);
}

/* 03 · Global scale — rebuilt as two columns -------------------------------
 *
 * The design puts the heading in the left column and runs the six figures down
 * the right, one under the next, which is why this band stands taller than a
 * screen rather than being the widescreen 3x2 grid it was.
 *
 * Everything above this point styled that grid. It is superseded here but not
 * deleted: .zouma-outcomes further down the page still uses the same
 * .zouma-statgrid classes — and its dot-expands-into-the-grid reveal — for its
 * own figures, so those rules are still load-bearing elsewhere.
 */
.zouma-stats {
  /* Opts out of the shared `main > section` screen-height floor, so the band
	 * is as tall as its own content and padding make it.
	 *
	 * Nothing in this file ever set a height on the section — the screenful
	 * came from that one shared rule at (0,0,2), which a class outranks. So the
	 * opt-out belongs here rather than as an edit to the shared rule, which
	 * every other band still wants. */
  min-height: 0;
  padding-block: clamp(3.5rem, calc(8 * var(--zouma-vw)), 7.5rem);
  /* These three reserved room for the old grid's overhanging rules. There is
	 * no frame here to overhang, so they collapse. */
  --zouma-overhang-x: 0px;
  --zouma-overhang-y: 0px;
  --zouma-head-gap: 0px;
  text-align: left;
}

.zouma-stats__grid {
  display: grid;
  grid-template-columns: minmax(0, 660fr) minmax(0, 500fr);
  gap: clamp(2rem, calc(8.3 * var(--zouma-vw)), 7.5rem);
  align-items: start;
}

/* Sticky, so the heading travels with the figures instead of scrolling away
 * and leaving a tall empty column beside them. Offset by the header, which
 * floats over the page and would otherwise cover it. */
.zouma-stats__head {
  position: sticky;
  top: calc(
    var(--zouma-header-h) + clamp(1.5rem, calc(3 * var(--zouma-vw)), 3rem)
  );
  margin-bottom: 0;
  text-align: left;
}

.zouma-stats .zouma-eyebrow {
  justify-content: flex-start;
}

.zouma-stats__title {
  max-width: 520px;
  margin: 20px 0 0;
  font-size: clamp(1.75rem, 1.05rem + calc(2.51 * var(--zouma-vw)), 3.3125rem);
  line-height: 1.13;
  letter-spacing: -0.01em;
  text-align: left;
}

.zouma-stats__lede {
  max-width: 640px;
  margin: clamp(1rem, calc(2.3 * var(--zouma-vw)), 2.0625rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.875rem, 0.74rem + calc(0.428 * var(--zouma-vw)), 1.125rem);
  line-height: 1.7;
}

/* One figure at a time.
 *
 * Every figure sits in the same grid cell rather than being stacked down the
 * column, so the box takes the height of the tallest of them once and holds it
 * — swapping figures cannot move the section. No absolute positioning and no
 * measured height: the grid works it out, which keeps it right when the copy
 * is edited or the column narrows.
 *
 * The inactive ones are visibility:hidden rather than opacity:0 alone, so a
 * screen reader is offered the figure on show and not all six at once. */
.zouma-stats__list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zouma-stat {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 260ms ease,
    visibility 0s linear 260ms;
}

.zouma-stat.is-active {
  opacity: 1;
  visibility: visible;
  transition:
    opacity 260ms ease,
    visibility 0s;
}

.zouma-stat__value {
  margin: 0;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  font-size: clamp(3.25rem, 2.75rem + calc(8.4 * var(--zouma-vw)), 10.3125rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
}

/* The "x" in 24x7 is wrapped in a span by the field value, and reads as a
 * multiplication sign rather than a digit — so it sits smaller and lighter. */
.zouma-stat__value span {
  font-size: 0.62em;
  font-weight: 400;
  vertical-align: 0.04em;
}

.zouma-stat__label {
  margin: clamp(0.75rem, calc(2.05 * var(--zouma-vw)), 1.875rem) 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.25rem, 1.25rem + calc(0.833 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-stat__text {
  margin: clamp(0.125rem, calc(0.35 * var(--zouma-vw)), 0.3125rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.875rem, 0.74rem + calc(0.428 * var(--zouma-vw)), 1.125rem);
  line-height: 1.6;
}

/* One column on a narrow screen, and the head stops sticking — a sticky
 * heading in a single-column stack would ride over the figures under it. */
@media (max-width: 900px) {
  .zouma-stats__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.75rem, calc(3.5 * var(--zouma-vw)), 2.5rem);
  }

  .zouma-stats__head {
    position: static;
  }
}

@media (max-width: 820px) {
  .zouma-stats {
    --zouma-overhang-y: 0px;
    --zouma-head-gap: 32px;
  }

  .zouma-statgrid__frame {
    margin-bottom: 0;
  }
}

/* 04 · Where instinct meets intelligence -----------------------------------
 *
 * Full-bleed photograph with a light card laid over its right side.
 *
 * Measured off the design at 1440: section 1440x762, card 471x321 with its
 * right edge 187px in from the viewport. --zouma-vw is capped at 14.4px, so
 * each calc arm lands on those figures at design width and scales down from
 * there — 13 x 14.4 = 187, 32.7 x 14.4 = 471, 52.9 x 14.4 = 762.
 *
 * This replaces a 50/50 split with the copy on a dark half in white type. The
 * photograph is no longer cut in half to make room for the words, and no scrim
 * is laid over it — the card carries the contrast instead, so the picture
 * stays as bright as it is in the design.
 */

.zouma-instinct {
  position: relative;
  display: grid;
  align-content: center;
  /* Raised to a full screen with the rest of the sections. The clamp this
	 * replaces was a proportional floor tuned to the design's height at 1728;
	 * a screen is the floor now, and the clamp's job is done. */
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
}

/* The backdrop. Absolute rather than a background-image so the file is a real
 * <img> — it can carry alt text, and the browser can lazy-load and size it. */
.zouma-instinct__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.zouma-instinct__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The shell is only being borrowed for its centring here — the card's inset is
 * measured from the viewport edge in the design, not from the 1320 container,
 * so the container's own max-width would put it 87px out. */
.zouma-instinct .zouma-shell {
  position: relative;
  z-index: 1;
  max-width: none;
  padding-inline: clamp(1.25rem, calc(13 * var(--zouma-vw)), 187px);
}

.zouma-instinct__card {
  width: clamp(17.5rem, calc(32.7 * var(--zouma-vw)), 471px);
  margin-left: auto;
  /* 40px at design width, not 32. Measured back from the body copy: the
	 * design wraps it to three lines inside a 471px card, which puts the text
	 * column at 389px and the padding at ~41px a side. At 32px the column ran
	 * 407px and the same sentence fitted on two lines. */
  padding: clamp(1.5rem, calc(2.8 * var(--zouma-vw)), 2.5rem);
  background: #fff;
  border-radius: 6px;
}

.zouma-instinct .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-instinct__title {
  margin: clamp(0.75rem, calc(1.3 * var(--zouma-vw)), 1rem) 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.4rem, 1.05rem + calc(1.2 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.16;
}

.zouma-instinct__text {
  margin: clamp(0.625rem, calc(1.1 * var(--zouma-vw)), 0.875rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: var(--zouma-size-body);
  font-weight: 400;
  line-height: 1.6;
}

/* Outlined, with the link colour carrying it rather than a filled block —
 * the design keeps this quiet against the white card. */
.zouma-instinct__cta {
  display: inline-block;
  margin-top: clamp(1rem, calc(1.8 * var(--zouma-vw)), 1.375rem);
  padding: 8px 16px;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  border: 1px solid #bfdcec;
  border-radius: 4px;
  transition:
    background-color 160ms ease,
    border-color 160ms ease;
}

.zouma-instinct__cta:hover,
.zouma-instinct__cta:focus-visible {
  background: #f2f9fd;
  border-color: var(--zouma-blue);
}

/* Narrow screens: the card stops floating and spans the column, so it never
 * gets too small to hold the heading on two lines. The photograph stays as the
 * backdrop behind it. */
@media (max-width: 860px) {
  .zouma-instinct {
    min-height: 0;
    padding-block: clamp(3rem, calc(7 * var(--zouma-vw)), 5rem);
  }

  .zouma-instinct__card {
    width: 100%;
    max-width: 34rem;
    margin-inline: auto;
  }
}

/* 06 · AI at the core ------------------------------------------------------
 *
 * Split down the middle, full bleed: photograph left, dark panel right.
 *
 * Measured off the design at 1440: section 1440x764, split at 718, panel copy
 * starting 65px inside the panel and running to a 474px column. --zouma-vw is
 * capped at 14.4px, so each calc arm lands on those figures at design width —
 * 53.1 x 14.4 = 764, 4.5 x 14.4 = 65, 32.9 x 14.4 = 474.
 *
 * Replaces a shell-contained layout with a portrait photo-mosaic on the right.
 * The tile decoration and the section-wide blue wash go with it: the panel is
 * its own dark field now, and the photograph supplies the light.
 */

.zouma-core {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  /* align-content, not just align-items.
	 *
	 * The shared `main > section` floor makes every section a screen tall and
	 * centres its rows with align-content: center. That is right for a section
	 * whose content is a centred stack, but this one is a full-bleed split: the
	 * photograph has to reach the top and bottom edges.
	 *
	 * align-items only stretches an item inside its own row, and the row here
	 * was sized to content (632px) then centred in the 1000px box, leaving 184px
	 * of background above and below the picture. Stretching the content instead
	 * grows the row itself to fill the section, and the photo with it. */
  align-content: stretch;
  /* Raised to a full screen with the rest of the sections. The clamp this
	 * replaces was a proportional floor tuned to the design's height at 1728;
	 * a screen is the floor now, and the clamp's job is done. */
  min-height: 100vh;
  min-height: 100svh;
  padding-block: 0;
  background: #04121b;
  color: #fff;
  overflow: hidden;
}

.zouma-core__media {
  position: relative;
  min-width: 0;
}

.zouma-core__media img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.zouma-core__panel {
  position: relative;
  display: grid;
  /* One column, never wider than the panel.
   *
   * With no template the implicit column is `auto`, which sizes to its
   * content — and .__copy carries an explicit width: 570px, so the column
   * took that width whatever the panel measured. At 1024 the panel is half
   * the screen, about 440px of content box, and the copy sat 130px wider
   * than it inside a section that clips: the ends of the heading and lede
   * were simply gone. minmax(0, 1fr) ties the column to the panel and lets
   * the max-width: 100% on .__copy do what it was written to do. */
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  min-width: 0;
  padding: clamp(2.5rem, calc(5 * var(--zouma-vw)), 4rem)
    clamp(1.25rem, calc(4.5 * var(--zouma-vw)), 65px);
  background: #04121b;
}

/* The dot field, kept from the old treatment — it is what tied this band to
 * the rest of the page and it still does. */
.zouma-core__glow {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(
    circle,
    rgba(173, 219, 243, 0.07) 1.1px,
    transparent 1.3px
  );
  background-size: 26px 26px;
  pointer-events: none;
}

/* The copy fills the panel between its paddings rather than stopping at a
 * 474px measure, which is what left the heading breaking mid-phrase. */
.zouma-core__copy {
  position: relative;
  z-index: 1;
  max-width: 100%;
  width: 570px;
}

.zouma-core .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-core__title {
  margin: clamp(0.75rem, calc(1.3 * var(--zouma-vw)), 1rem) 0 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.22;
}

.zouma-core__lede {
  margin: clamp(0.625rem, calc(1.1 * var(--zouma-vw)), 0.875rem) 0 0;
  color: var(--zouma-sky);
  font-family: var(--zouma-font-body);
  font-size: var(--zouma-size-body);
  font-weight: 400;
  line-height: 1.6;
}

/* Three across, as the design has them. */
/* Wider than the copy above it, and capped so it does not sprawl on a large
 * screen. Its own measure, because three cards need more room across than a
 * paragraph wants to be read at — inside the copy's 474px they come out around
 * 145px each and the body text wraps to five lines. It sits outside .__copy in
 * the markup, so this width is free to exceed it.
 *
 * position/z-index to match .__copy: the panel's glow is a sibling of both, and
 * without them the cards would fall behind it. */
.zouma-core__cards {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* 8px between the cards.
	 *
	 * The max-width is sized to match — three cards plus two gaps — so the
	 * cards keep their own width (193px at design size) and only the space
	 * between them changes, rather than the cards growing to fill a fixed
	 * row. */
  gap: clamp(0.5rem, calc(0.56 * var(--zouma-vw)), 8px);
  max-width: clamp(18rem, calc(41.4 * var(--zouma-vw)), 596px);
  margin: clamp(1.5rem, calc(2.7 * var(--zouma-vw)), 2.4rem) 0 0;
  padding: 0;
  list-style: none;
}

.zouma-core__card {
  min-width: 0;
  padding: clamp(1rem, calc(1.6 * var(--zouma-vw)), 22px);
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid rgba(173, 219, 243, 0.16);
  border-radius: 10px;
}

/* The mark carries the card. It is roughly twice the title's size in the
 * design, drawn as a blue outline, and sits above the copy with air under it.
 * currentColor rather than a fill on the file, so a supplied SVG is tinted by
 * this rule and a supplied PNG can arrive already coloured — either works. */
.zouma-core__card-mark {
  display: block;
  width: clamp(30px, calc(2.6 * var(--zouma-vw)), 38px);
  height: clamp(30px, calc(2.6 * var(--zouma-vw)), 38px);
  margin-bottom: clamp(0.75rem, calc(1.1 * var(--zouma-vw)), 1rem);
  color: var(--zouma-cyan);
}

.zouma-core__card-mark img,
.zouma-core__card-mark .zouma-icon {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.zouma-core__card-title {
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(0.95rem, calc(1.15 * var(--zouma-vw)), 1.0625rem);
  font-weight: 700;
  line-height: 1.3;
}

/* Light blue rather than the grey it was: in the design the body copy on these
 * cards is the same sky the rest of the dark sections use, not a neutral. */
.zouma-core__card-text {
  margin: 0.5rem 0 0;
  color: var(--zouma-sky);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.8rem, calc(0.92 * var(--zouma-vw)), 0.875rem);
  font-weight: 400;
  line-height: 1.55;
}

/* Too narrow to split: the photograph goes full width above the panel. */
@media (max-width: 900px) {
  .zouma-core {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
  }

  .zouma-core__media {
    aspect-ratio: 16 / 10;
  }

  /* Once the split collapses, the panel is the full width and the copy is
	 * given a wider measure. The cards take the same one — they are a sibling
	 * of the copy now, so they no longer pick this up by inheritance, and
	 * without it they would come out narrower here than on a desktop. */
  .zouma-core__copy,
  .zouma-core__cards {
    /* min() rather than a flat 34rem: 34rem is 544px, which is wider than
     * any phone. Below about 600px this overrode the base max-width: 100%
     * and pushed the heading, the lede and the cards to 544px inside a
     * ~280px panel, where .zouma-core's overflow: hidden cut them off with
     * nothing to show it had happened. The wider measure still applies
     * wherever there is room for it. */
    max-width: min(34rem, 100%);
  }
}

@media (max-width: 560px) {
  .zouma-core__cards {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* 05 · Transformation journey ---------------------------------------------
 *
 * Replaces the pinned scroll track that used to live here — a full-bleed photo
 * on the left and steps on the right that swapped one at a time as the section
 * held the viewport. It cost 2800px of page to buy that scroll distance, and
 * with the reveal inactive every step painted on top of the last.
 *
 * The design wants the five stages read at a glance, on one line, between the
 * instinct card and the AI-at-the-core panel. So: a centred head, then a rail
 * of equal columns. Nothing pins, nothing animates, no JavaScript is involved.
 */

.zouma-journey {
  /* The frame measures 625 tall: 80 above the eyebrow, the stages ending on
	 * their rules at 505, and the rest below. */

  /* Sized by that content, not by the viewport.
	 *
	 * The blanket min-height on every top-level section was holding this one
	 * to a full screen, and the stages read as a single line — 623px of content
	 * in a 900px box left 277px of empty page under them. auto rather than a
	 * smaller fixed floor because on a phone the content already runs past the
	 * viewport, and this has to shrink and grow with it either way.
	 *
	 * The grid and its centring from that rule are deliberately left alone:
	 * with no slack there is nothing left to centre, and switching the display
	 * back to block would change how these children meet the padding below. */
  min-height: auto;
  padding-block: clamp(3rem, calc(6.67 * var(--zouma-vw)), 6rem)
    clamp(3rem, calc(8.3 * var(--zouma-vw)), 7.5rem);
  background: #fff;
  text-align: left;
}

/* The band runs on the same 1280 column as the rest of the page, which is what
 * the five 256 stage columns are measured from. */
.zouma-journey .zouma-shell {
  max-width: 1360px;
}

.zouma-journey .zouma-eyebrow {
  justify-content: flex-start;
  margin-bottom: 7px;
}

.zouma-journey__title {
  max-width: 1100px;
  margin: 0;
  color: #121212;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.75rem, 1.05rem + calc(2.31 * var(--zouma-vw)), 3.125rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

/* The trademark rides high and small, as it does in the frame. */
.zouma-journey__title sup {
  font-size: 0.44em;
  vertical-align: 0.9em;
}

.zouma-journey__lede {
  max-width: 900px;
  margin: clamp(0.5rem, calc(0.83 * var(--zouma-vw)), 0.75rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.8125rem, 0.75rem + calc(0.22 * var(--zouma-vw)), 0.875rem);
  line-height: 1.7;
}

/* The stage grid.
 *
 * One equal column per stage — five of them fill the 1280 column at 256 each,
 * which is what puts the divisions where the frame has them. The columns are
 * contiguous rather than gapped: the rule between two stages IS the division,
 * so a gap would leave it floating between them.
 *
 * The column count comes from the markup so the grid still divides evenly if a
 * stage is added or removed in the admin. */
.zouma-journey__track {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--zouma-journey-cols, 5), minmax(0, 1fr));
  gap: 0;
  margin: clamp(2.5rem, calc(4.6 * var(--zouma-vw)), 4.125rem) 0 0;
  padding: 0;
  list-style: none;
}

/* The rail, bled to the width of the screen while the stages stay on the
 * shell. It fades out towards both edges rather than stopping on a hard end,
 * so it reads as a horizon behind the section rather than a drawn rule. */
.zouma-journey__track::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 100vw;
  height: 2px;
  transform: translateX(-50%);
  background: linear-gradient(
    90deg,
    rgba(199, 228, 246, 0) 0%,
    var(--zouma-sky-soft) 13%,
    var(--zouma-sky-soft) 87%,
    rgba(199, 228, 246, 0) 100%
  );
}

/* The travelled part of the rail.
 *
 * Sits on the track rather than on the full-bleed rail above, so it starts at
 * the beginning of the timeline and ends exactly on a node — the nodes sit on
 * their column's left edge, so stage N is at (N-1)/columns across.
 *
 * Width is what animates, which is what gives the left-to-right fill: the
 * element is anchored at the left, so growing it can only sweep rightwards.
 * A background-position or transform sweep would need a fixed end point, and
 * this one moves with whichever stage is hovered. */
.zouma-journey__track::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  height: 2px;
  width: var(--zouma-journey-fill, 0%);
  background: var(--zouma-blue);
  transition: width 420ms cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

/* How far the fill runs, per hovered stage.
 *
 * :has() is what lets the track react to which of its own children is under
 * the cursor — the fill lives on the parent, the hover happens on a child.
 * Written against --zouma-journey-cols rather than hard-coded percentages so
 * the stops stay correct if the number of stages changes.
 *
 * Stage 1 fills to zero: it is the beginning of the line, so there is nothing
 * behind it to travel. Its node and its rule still light up. */
.zouma-journey__track:has(.zouma-journey__step:nth-child(1):hover) {
  --zouma-journey-fill: 0%;
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(2):hover) {
  --zouma-journey-fill: calc(1 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(3):hover) {
  --zouma-journey-fill: calc(2 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(4):hover) {
  --zouma-journey-fill: calc(3 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(5):hover) {
  --zouma-journey-fill: calc(4 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(6):hover) {
  --zouma-journey-fill: calc(5 / var(--zouma-journey-cols, 5) * 100%);
}

/* Keyboard parity, so the timeline is not mouse-only. */
.zouma-journey__track:has(.zouma-journey__step:nth-child(2):focus-within) {
  --zouma-journey-fill: calc(1 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(3):focus-within) {
  --zouma-journey-fill: calc(2 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(4):focus-within) {
  --zouma-journey-fill: calc(3 / var(--zouma-journey-cols, 5) * 100%);
}
.zouma-journey__track:has(.zouma-journey__step:nth-child(5):focus-within) {
  --zouma-journey-fill: calc(4 / var(--zouma-journey-cols, 5) * 100%);
}

/* The fill is the whole point of the interaction, so under reduced motion it
 * still moves — it just arrives without the sweep. */
@media (prefers-reduced-motion: reduce) {
  .zouma-journey__track::after,
  .zouma-journey__marker {
    transition: none;
  }
}

/* min-height rather than the copy's own height: the frame runs the divisions
 * past the last line of text, and every rule ends level whatever a stage says. */
.zouma-journey__step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  min-height: clamp(9rem, calc(15.4 * var(--zouma-vw)), 13.875rem);
  padding: clamp(2.25rem, calc(3.54 * var(--zouma-vw)), 3.1875rem)
    clamp(0.75rem, calc(1.6 * var(--zouma-vw)), 1.5rem) 0;
}

/* No vertical rule under the hovered stage, and none at rest either. The
 * timeline is the row of nodes and the line through them; the hover state is
 * carried by the node and by the travelled part of that line. */

/* The node where a column meets the rail, centred on the column's own edge. */
.zouma-journey__marker {
  position: absolute;
  top: -4px;
  left: -5px;
  /* Above the rail and above the fill that runs under it. */
  z-index: 2;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--zouma-sky-soft);
  transition: background-color 260ms ease;
}

/* The hovered stage: its node takes the active blue. Only the hovered one —
 * the stages before it stay light, with the filled rail alone showing how far
 * along the timeline you are. */
.zouma-journey__step:hover .zouma-journey__marker,
.zouma-journey__step:focus-within .zouma-journey__marker {
  background: var(--zouma-blue);
}

.zouma-journey__num {
  margin: 0;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.75rem, 0.71rem + calc(0.22 * var(--zouma-vw)), 0.875rem);
  font-weight: 400;
  line-height: 1.4;
}

.zouma-journey__name {
  margin: clamp(0.625rem, calc(1.25 * var(--zouma-vw)), 1.125rem) 0 0;
  color: #121212;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.25rem, 0.95rem + calc(1.167 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.zouma-journey__copy {
  margin: clamp(0.5rem, calc(0.9 * var(--zouma-vw)), 0.8125rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.8125rem, 0.75rem + calc(0.22 * var(--zouma-vw)), 0.875rem);
  line-height: 1.5;
}

/* Below the point where five columns stop holding a readable line of copy, the
 * rail turns vertical: the rule runs down the left, the markers sit on it, and
 * each stage reads as a row. Same structure, rotated — no second markup. */
/* Five columns hold to about a laptop; below that the copy stops fitting a
 * readable line, so the grid halves and then goes to one. The divisions follow
 * the columns, so the rules land between whatever is beside what. */
@media (max-width: 1180px) {
  .zouma-journey__track {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  /* The travelled rail only means anything while the stages are on one line.
	 * Once they wrap, a bar across the top of the grid measures the first row
	 * and nothing else, so it is withdrawn. The node and the stage's own rule
	 * still light up, which is what carries the interaction at these widths. */
  .zouma-journey__track::after {
    display: none;
  }

  /* Rows after the first are divided by their top edge. There are no vertical
	 * rules to reset here any more. */
  .zouma-journey__step:nth-child(n + 4) {
    border-top: 2px solid #e5f2fb;
  }
}

@media (max-width: 820px) {
  .zouma-journey__track {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .zouma-journey__step:nth-child(n) {
    border-top: 0;
  }

  .zouma-journey__step:nth-child(n + 3) {
    border-top: 2px solid #e5f2fb;
  }
}

/* One stage per row. The rail turns into the left-hand rule the nodes sit on,
 * which is the same idea stood on its end. */
@media (max-width: 560px) {
  .zouma-journey__track {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-journey__track::before {
    left: 0;
    width: 2px;
    height: 100%;
    transform: none;
    background: linear-gradient(
      180deg,
      var(--zouma-sky-soft) 0%,
      var(--zouma-sky-soft) 88%,
      rgba(199, 228, 246, 0) 100%
    );
  }

  .zouma-journey__step,
  .zouma-journey__step:nth-child(n) {
    min-height: 0;
    padding: 0 0 clamp(1.5rem, calc(3 * var(--zouma-vw)), 2.25rem) 26px;
    border-top: 0;
  }

  .zouma-journey__step:last-child {
    padding-bottom: 0;
  }

  .zouma-journey__marker {
    top: 6px;
    left: -4px;
  }
}

/* =========================================================================
 * 07 · What We Do / Four pillars — tabbed.
 *
 * Measured off the design at 1440: content column 1113px centred (narrower
 * than the 1320 shell, so it is capped here), rail underlined at its foot with
 * the selected tab carrying a heavier blue rule, panel photo 534x402.
 *
 * Replaces a row of four equal cards plus a separate managed-offshore feature
 * block below them. The block is the first tab's panel now, so the same words
 * appear once instead of twice, and the two head CTAs go with it — the design
 * puts one call to action inside each panel instead.
 * ====================================================================== */

.zouma-pillars {
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 6rem);
  background: #fff;
}

/* Full shell width.
 *
 * This band used to carry a 1113px inset of its own, which left it visibly
 * narrower than every other section on the page and pinned it to that figure
 * on any viewport wide enough to give it more. It now takes the same 1320px
 * the shell uses, and stays fluid below that.
 *
 * The cap never actually binds — .zouma-shell is already 1320px and its
 * padding sits inside that, so the band renders at the shell's content width
 * like every other section. It is stated anyway so the intended figure is
 * visible here and the old inset is not reintroduced by accident. */
.zouma-pillars__inner {
  width: 100%;
  max-width: 1320px;
  margin-inline: auto;
}

.zouma-pillars__title {
  margin: clamp(0.75rem, calc(1.4 * var(--zouma-vw)), 1.125rem) 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.05rem + calc(1.55 * var(--zouma-vw)), 2.25rem);
  font-weight: 700;
  line-height: 1.24;
}

/* The rail.
 *
 * The hairline runs under the whole row rather than under each tab, so the
 * selected tab's heavier rule sits on a continuous line instead of in a gap.
 * overflow-x lets the four labels scroll rather than wrap on a narrow screen —
 * wrapping would break the single-line rail the design depends on. */
.zouma-pillars__rail {
  display: flex;
  gap: clamp(1.25rem, calc(2.6 * var(--zouma-vw)), 2.75rem);
  margin-top: clamp(1.75rem, calc(3.4 * var(--zouma-vw)), 3rem);
  border-bottom: 1px solid #e4e9ee;
  overflow-x: auto;
  scrollbar-width: none;
}

.zouma-pillars__rail::-webkit-scrollbar {
  display: none;
}

/* Entrance.
 *
 * The rail is laid out at full size as soon as the page renders, but the reveal
 * on it (data-zouma-reveal="up stagger") animates its children — so for the
 * length of the entrance the hairline was drawn at full strength under four
 * labels still at opacity 0: an empty bordered strip, which is the "extra line"
 * this was reported as. The rail is faded on the same timeline as the tabs, so
 * the rule arrives with the labels it belongs to; the stagger inside it is
 * untouched.
 *
 * :has() reads the state main.js already writes rather than introducing a
 * second mechanism, and both rules stop matching when the reveal takes its
 * classes off again — after which the rail is exactly what the base rule says.
 *
 * The pose carries no transition, as the shared vocabulary's does not: the two
 * together would fade the rail *out* the moment the section was armed. */
.zouma-pillars__rail:has(> .is-enter) {
  opacity: 0;
  transition: none;
}

/* The shared reveal's own opacity ramp, undelayed — the rule comes up with the
 * first label rather than as a second event. */
.zouma-pillars__rail:has(> .is-enter.is-in) {
  opacity: 1;
  transition: opacity 720ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* Reduced motion never arms the reveal, so nothing above can match; this is the
 * backstop for markup that somehow arrives already carrying the classes, the
 * same one the shared vocabulary keeps. */
@media (prefers-reduced-motion: reduce) {
  .zouma-pillars__rail:has(> .is-enter) {
    opacity: 1;
  }
}

.zouma-pillars__tab {
  position: relative;
  flex: 0 1 auto;
  max-width: 15rem;
  margin: 0;
  padding: 0 0 clamp(0.625rem, calc(1.1 * var(--zouma-vw)), 0.875rem);
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  background: none;
  border: 0;
  /* Square. Buttons inherit a radius from the global button styling, which
	 * bows the 2px rule into a curve under the label. */
  border-radius: 0;
  /* Sits on the rail's own hairline rather than beside it. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  transition:
    color 160ms ease,
    border-color 160ms ease;
}

/* Hover ------------------------------------------------------------------
 *
 * Two layers, both on pseudo-elements so the rail's spacing is untouched:
 * a wash that lifts the tab off the page, and the rule that draws in under it.
 *
 * The rule is a scaled transform rather than an animated width — it runs on
 * the compositor, and a width animation on a flex child could nudge the row.
 * Bled past the label horizontally so the wash has room without giving the
 * button padding it does not otherwise have. */
.zouma-pillars__tab::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

/* Sits on the tab's own 2px border line, which is where the selected tab's
 * rule is drawn — so hovering and selecting put the line in the same place. */
.zouma-pillars__tab::after {
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--zouma-blue);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 240ms cubic-bezier(0.33, 0, 0.2, 1);
}

/* The theme fills any button with the dark brand blue on hover (see the
 * button:hover rule in style.css). These tabs are labels rather than buttons in
 * that sense, so the fill is turned off — the base rule sets background:none but
 * loses to button:hover, which is more specific. Outside the pointer query so a
 * tap on a touch screen cannot leave the fill behind either. */
.zouma-pillars__tab:hover,
.zouma-pillars__tab:focus,
.zouma-pillars__tab:focus-visible {
  /* The theme fills any button with the dark brand blue on hover (see the
	 * button:hover rule in style.css). That is the dark block these tabs were
	 * picking up: the base rule sets background:none but loses to button:hover,
	 * which is more specific. Replaced with the palest blue in the palette so
	 * the tab lifts off the page without ever going dark. */
  background: var(--zouma-blue-tint);
}

/* Pointer devices only: on a touch screen :hover sticks after a tap, which
 * would leave the wash sitting under a tab nobody is pointing at. */
@media (hover: hover) {
  .zouma-pillars__tab:hover {
    color: var(--zouma-color-text);
  }

  .zouma-pillars__tab:hover::after {
    transform: scaleX(1);
  }
}

/* Homepage only: real padding inside the tab, with the wash on the tab itself.
 *
 * Scoped to .home because the Industries rail reuses this class and is not part
 * of this change.
 *
 * Carried by the homepage rail and by the Industries one, which is meant to be
 * the same section. Every selector below names both; the .home half is
 * unchanged, so nothing about the homepage moves.
 *
 * Two things had to be handled for padding to be safe here.
 *
 * The tab is border-box and capped at 15rem, and the first two labels sit
 * exactly at that cap - so padding would have come out of the label's own
 * width and moved where it wraps, changing the tab heights. The cap grows by
 * exactly the horizontal padding, so the text keeps the width it had.
 *
 * And the rail carries no gap at all: the space between two labels is the
 * right padding of one tab plus the left padding of the next, so each tab is
 * given half the old gap and label-to-label spacing across the row comes out
 * unchanged. Every pixel between the labels now belongs to a tab, which is
 * what lets the hover wash fill it. */
.home .zouma-pillars__rail,
.zouma-wwdpillars .zouma-pillars__rail,
.zouma-indpillars .zouma-pillars__rail {
	/* Exactly half the gap this rail used to carry, so two neighbouring tabs put
	 * back the same distance between their labels that the gap did - now as
	 * padding inside each tab, where the hover wash can cover it. */
	--zouma-tab-pad-x: clamp(0.625rem, calc(1.3 * var(--zouma-vw)), 1.375rem);
	--zouma-tab-pad-y: clamp(0.5rem, calc(0.8 * var(--zouma-vw)), 0.75rem);

	/* The padding is the whole of the spacing now. */
	gap: 0;
}

.home .zouma-pillars__tab,
.zouma-wwdpillars .zouma-pillars__tab,
.zouma-indpillars .zouma-pillars__tab {
	padding-top: var(--zouma-tab-pad-y);
	padding-inline: var(--zouma-tab-pad-x);
	max-width: calc(15rem + 2 * var(--zouma-tab-pad-x));
}

/* The wash is the tab's own background, so it covers the padded box exactly -
 * and the rule under it already spans the tab's full width, so it grows with
 * the wash and stays aligned to it.
 *
 * The same three states as the shared rule above, and outside the pointer query
 * for the same reason that one is: :focus stays on a tab after it is clicked,
 * and a tap on a touch screen has no :hover to match. Either would otherwise
 * fall through to the paler shared tint and read as the wrong colour. */
.home .zouma-pillars__tab:hover,
.home .zouma-pillars__tab:focus,
.home .zouma-pillars__tab:focus-visible,
.zouma-wwdpillars .zouma-pillars__tab:hover,
.zouma-wwdpillars .zouma-pillars__tab:focus,
.zouma-wwdpillars .zouma-pillars__tab:focus-visible,
.zouma-indpillars .zouma-pillars__tab:hover,
.zouma-indpillars .zouma-pillars__tab:focus,
.zouma-indpillars .zouma-pillars__tab:focus-visible {
	/* Fades in downward, so the wash reads as growing out of the blue rule and
	 * reaches the exact tone at the bottom edge, where the rule meets it. The
	 * transparent stop is the same colour at zero alpha rather than plain
	 * transparent - Safari interpolates through black otherwise, which greys the
	 * middle of the fade. Shorthand, so it also clears the flat background-color
	 * the shared rule above sets. */
	background: linear-gradient(180deg, rgba(225, 237, 249, 0) 0%, #e1edf9 100%);
}

.zouma-pillars__tab.is-active {
  color: var(--zouma-color-text);
  border-bottom-color: var(--zouma-blue);
}

.zouma-pillars__tab:focus-visible {
  outline: 2px solid var(--zouma-blue);
  outline-offset: 3px;
}

/* The open panel. Copy left, photograph right. */
.zouma-pillars__panel {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* Top-aligned, as the design has it — the pillar label sits level with
	 * the top edge of the photograph. */
  align-items: start;
  gap: clamp(1.75rem, calc(3.6 * var(--zouma-vw)), 3.5rem);
  margin-top: clamp(2rem, calc(4 * var(--zouma-vw)), 3.5rem);
}

/* [hidden] is only a display:none in the UA sheet, and display:grid above wins
 * over it — without this the closed panels would all stay open. */
.zouma-pillars__panel[hidden] {
  display: none;
}

.zouma-pillars__copy {
  min-width: 0;
}

.zouma-pillars__name {
  /* Every pillar title on one line.
	 *
	 * The names were shortened for the tab rail, and at 19ch (441px at 1440)
	 * the cap — not the column — was what still broke the two longest of them
	 * across two lines: "Managed Offshore Operations" measures 13.56em and
	 * "Business Process Automation" 13.41em, against a cap worth 12.26em.
	 *
	 * The column is not the problem and the type does not have to shrink: the
	 * copy half of the panel runs 594px at 1440 and 429px at 950, so the
	 * longest title clears it at every width the two-column layout is on. The
	 * cap is simply raised past what the words need — 23ch is 14.83em, ~10%
	 * of headroom over the 13.56em worst case — and still lands short of the
	 * column, so it goes on holding a longer CMS title to a sane measure
	 * instead of letting a heading run the full width of the panel.
	 *
	 * Not nowrap: this has to give way on a narrow screen rather than push the
	 * grid child past the viewport, where .zouma-site clips it with no
	 * scrollbar to show for it.
	 *
	 * ch rather than px so it tracks the clamped font-size across breakpoints;
	 * dropped entirely under 900px, where the panel is a single column. */
  max-width: 23ch;
  margin: clamp(0.75rem, calc(1.4 * var(--zouma-vw)), 1.125rem) 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.05rem + calc(1.55 * var(--zouma-vw)), 2.25rem);
  font-weight: 700;
  line-height: 1.22;
}

.zouma-pillars__text {
  /* max-width: 44ch; */
  margin: clamp(0.875rem, calc(1.6 * var(--zouma-vw)), 1.25rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: var(--zouma-size-body);
  font-weight: 400;
  line-height: 1.75;
}

/* The services under each pillar.
 *
 * Pills rather than the bulleted list they were: the design sets them as a
 * wrapping row of tinted chips, which reads as a set of capabilities at a
 * glance instead of as a second paragraph under the first.
 *
 * flex-wrap, not a grid: the labels run from "NOC/SOC" to "CRM & Business
 * Process Support", and fixed columns would size every chip to the longest of
 * them. Wrapping lets each take the width of its own words and the row breaks
 * where it runs out.
 */
.zouma-pillars__services {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: clamp(1rem, calc(1.8 * var(--zouma-vw)), 1.375rem) 0 0;
  padding: 0;
  list-style: none;
}

.zouma-pillars__services li {
  padding: 8px 14px;
  color: #37424c;
  font-family: var(--zouma-font-body);
  font-size: clamp(0.75rem, 0.71rem + calc(0.2 * var(--zouma-vw)), 0.8125rem);
  font-weight: 500;
  line-height: 1.35;
  background: var(--zouma-blue-pale);
  border-radius: 6px;
}
.zouma-pillars__copy .zouma-btn {
  margin-top: clamp(1.25rem, calc(2.4 * var(--zouma-vw)), 1.875rem);
}

/* No aspect-ratio alongside the minimum — it would transfer through into a
 * minimum width and push the photo out of its column, as it did on the Who is
 * Zouma figure. Height sizes the box; cover absorbs the shape. */
.zouma-pillars__figure {
  margin: 0;
  min-width: 0;
  max-width: 100%;
  /* height, not min-height.
	 *
	 * With only a minimum the box is auto-height, so the image's height: 100%
	 * has no definite parent to resolve against and falls back to the file's
	 * own aspect ratio — object-fit: cover never gets a box to crop into. The
	 * four source images run from 0.44 to 1.46 tall, so pillar 02 (portrait,
	 * 1368x2000) rendered 776px against the others' 402. A definite height
	 * gives every panel the same frame and lets cover do its job. */
  height: clamp(14rem, calc(27.9 * var(--zouma-vw)), 402px);
  overflow: hidden;
  border-radius: 8px;
}

.zouma-pillars__figure img {
  display: block;
  width: 100%;
  height: 100%;
  /* min-height: inherit removed with the change above — it was what floored
	 * the short images at 402 while letting the tall one grow past it. */
  object-fit: cover;
}

@media (max-width: 900px) {
  .zouma-pillars__panel {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-pillars__name,
  .zouma-pillars__text {
    max-width: none;
  }

  .zouma-pillars__figure {
    height: clamp(12rem, 34vh, 18rem);
  }
}

/* =========================================================================
 * 08 · Live Now / Follow-the-Sun.
 *
 *   Cards   250×242 · #FFF · 1px #E4E9EE · 8px radius · 16px padding · 8px gap
 *   Time    "HH:MM" Albert Sans 700 · 48px  +  ":SS" Poppins 500 · 14 · #5B6770
 *   Weather box 1px #E4E9EE · 4px radius · 8px padding
 *   Foot    10/600 Poppins, green status dot
 *   CTA bar 870×106 · #E1EDF9 · 1px #ADDBF3 · 8px radius · 16/24 padding
 * ====================================================================== */

.zouma-sun {
  /* The clocks and the bar beneath them are one block in the design, so they
	 * share a width rather than each carrying its own number — the bar was set
	 * to 870px against the clocks' 1280px and sat visibly narrow. */
  --zouma-sun-width: 1280px;

  padding-block: 120px;
  background: #fff;
}

.zouma-sun__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  max-width: 870px;
  margin: 0 auto 40px;
  text-align: center;
}

.zouma-sun .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-sun .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-sun__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-sun__lede {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
}

/* Cards ------------------------------------------------------------------ */

.zouma-clocks {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
  max-width: var(--zouma-sun-width, 1280px);
  margin: 0 auto 40px;
  padding: 0;
  list-style: none;
}

.zouma-clock {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  background: #fff;
  border: 1px solid #e4e9ee;
  border-radius: 8px;
  text-align: left;
}

.zouma-clock__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.zouma-clock__place {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.zouma-clock__city {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
}

/* The artwork is a circular flag on a square canvas, so keep the box square
 * and contain it — cover would crop the top and bottom off the circle. */
.zouma-clock__flag {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  object-fit: contain;
  border-radius: 0;
}

.zouma-clock__country {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 400;
  line-height: 1.6;
}

/* Day/night badge -------------------------------------------------------- */

.zouma-clock__phase {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
  color: #f0a02a;
}

.zouma-clock__phase[data-phase="dawn"],
.zouma-clock__phase[data-phase="dusk"] {
  color: #ef8a3c;
}

.zouma-clock__phase[data-phase="night"] {
  color: var(--zouma-blue);
}

.zouma-clock__phase-label {
  font-family: var(--zouma-font-body);
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* One glyph per phase: sunrise, sun, sunset, moon. All four are in the
 * markup; only the one matching data-phase is shown. */
.zouma-clock__phase-icon .zouma-icon {
  display: none;
}

.zouma-clock__phase[data-phase="dawn"] .is-dawn,
.zouma-clock__phase[data-phase="day"] .is-day,
.zouma-clock__phase[data-phase="dusk"] .is-dusk,
.zouma-clock__phase[data-phase="night"] .is-night {
  display: block;
}

/* Before the script runs there is no data-phase; show the sun so the card
 * never renders with an empty slot. */
.zouma-clock__phase:not([data-phase]) .is-day {
  display: block;
}

/* Time ------------------------------------------------------------------- */

.zouma-clock__time {
  display: flex;
  align-items: baseline;
  gap: 1px;
  margin: 0;
  color: #000;
  font-variant-numeric: tabular-nums;
}

.zouma-clock__hm {
  font-family: var(--zouma-font-heading);
  font-size: clamp(2rem, 1.4rem + calc(1.6 * var(--zouma-vw)), 3rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.zouma-clock__sec {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 500;
}

/* Weather ---------------------------------------------------------------- */

.zouma-clock__weather {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px;
  border: 1px solid #e4e9ee;
  border-radius: 4px;
}

.zouma-clock__weather .zouma-icon {
  flex: 0 0 auto;
  color: #f0a02a;
}

.zouma-clock__weather .zouma-icon--cloud,
.zouma-clock__weather .zouma-icon--rain,
.zouma-clock__weather .zouma-icon--moon {
  color: var(--zouma-cyan);
}

.zouma-clock__temp {
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  font-weight: 600;
}

.zouma-clock__cond {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.5625rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.zouma-clock__note {
  margin: 0;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-body);
  font-size: 0.65rem;
  font-weight: 400;
  line-height: 1.5;
}

/* Footer row ------------------------------------------------------------- */

.zouma-clock__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
  padding-top: 4px;
}

.zouma-clock__shift,
.zouma-clock__agents {
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.zouma-clock__shift {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.zouma-clock__pulse {
  width: 6px;
  height: 6px;
  background: #22c55e;
  border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.6);
  animation: zouma-pulse 2s infinite;
}

/* CTA bar ---------------------------------------------------------------- */

.zouma-sunbar {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(24px, calc(4 * var(--zouma-vw)), 96px);
  max-width: var(--zouma-sun-width, 1280px);
  margin: 0 auto;
  padding: 16px 24px;
  background: var(--zouma-blue-pale);
  border: 1px solid var(--zouma-sky);
  border-radius: 8px;
  text-align: left;
}

.zouma-sunbar__copy {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.zouma-sunbar__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
}

.zouma-sunbar__note {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
}

.zouma-sunbar .zouma-btn--dark {
  flex: 0 0 auto;
}

@media (max-width: 1080px) {
  .zouma-clocks {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .zouma-sun {
    padding-block: clamp(3rem, calc(9 * var(--zouma-vw)), 6rem);
  }

  .zouma-clocks {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .zouma-sunbar {
    flex-wrap: wrap;
  }
}

@media (max-width: 460px) {
  .zouma-clocks {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* =========================================================================
 * 10 · Let's Build Together.
 *
 * Reuses the .zouma-statgrid component from section 03 with four columns and
 * a single row: 245px cells, 100px horizontal / 80px vertical overhang.
 * ====================================================================== */

.zouma-outcomes {
  --zouma-overhang-x: 100px;
  --zouma-overhang-y: 80px;
  --zouma-head-gap: 40px;

  padding-block: 120px;
  background: #fff;
}

.zouma-outcomes__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  max-width: 870px;
  /* Clear the 40px gap plus the rules that overhang above the cells. */
  margin: 0 auto calc(var(--zouma-head-gap) + var(--zouma-overhang-y));
  text-align: center;
}

.zouma-outcomes .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-outcomes .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-outcomes__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-outcomes__lede {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
}

.zouma-outcomes__head .zouma-btn--dark {
  margin-top: 16px;
}

/* Four 245px columns rather than the three 326px ones in section 03. */
.zouma-outcomes .zouma-statgrid__frame {
  max-width: 980px;
  margin-bottom: var(--zouma-overhang-y);
}

@media (max-width: 900px) {
  .zouma-outcomes {
    --zouma-overhang-y: 0px;
    --zouma-head-gap: 32px;
    padding-block: clamp(3rem, calc(9 * var(--zouma-vw)), 6rem);
  }

  .zouma-outcomes .zouma-statgrid__frame {
    margin-bottom: 0;
  }
}

/* =========================================================================
 * 11 · Client Testimonials.
 *
 *   Section  near-black · 120px padding · centred head 640px above the rail
 *   Cards    four across, no card chrome at all — the quote, the attribution,
 *            the client's logo and the result badge sit straight on the panel,
 *            separated by space rather than by a box
 *   Quote    Poppins 400 · 13/1.6 · 88% white
 *   Result   #0E85B6 · 6px radius · value left, label and note stacked right
 *   Arrows   36px circles, outlined, centred under the rail
 *
 * The rail still scrolls a card at a time; with four testimonials and four
 * columns there is simply nothing to scroll, and the arrows disable
 * themselves. Add a fifth and it comes to life.
 * ====================================================================== */

.zouma-testimonials {
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 7.5rem);
  background: #0a0e12;
  overflow: hidden;
}

.zouma-testimonials__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  max-width: 900px;
  margin: 0 auto clamp(2.25rem, calc(4 * var(--zouma-vw)), 3.5rem);
  text-align: center;
}

.zouma-testimonials .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-testimonials .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-testimonials__title {
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 0.9rem + calc(2.34 * var(--zouma-vw)), 3rem);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.zouma-testimonials__lede {
  margin: 0;
  color: rgba(255, 255, 255, 0.6);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.75rem, 0.71rem + calc(0.22 * var(--zouma-vw)), 0.875rem);
  font-weight: 400;
  line-height: 1.6;
}

/* Rail -------------------------------------------------------------------- */

/* The rail is the width of the shell and clips at its edges, so the columns
 * land exactly on the grid the rest of the page uses.
 *
 * Cards are sized from the scroller, not from the track: the track is a flex
 * row whose width comes from its children, so a percentage basis on a card
 * would be measuring itself. `cqi` reads the scroller's inline size instead,
 * which is the number that actually matters. The clamp above it is the
 * fallback for anything without container query units. */
.zouma-quotes {
  --zouma-gap: 9px;
  /* Three visible at a time, with the fourth cut off at the rail's edge to
   * show there is more to scroll to. The column count is the only figure that
   * has to change: the cards divide whatever the scroller measures, the arrows
   * read a card's real width at click time, and the breakpoints below step
   * down from here. */
  --zouma-quotes-cols: 3;
  --zouma-quotes-gutter: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);

  container-type: inline-size;

  /* The gutter is width, not padding.
   *
   * Padding on a scroll container does not clip what overflows it — the strip
   * of page inside padding-inline-end is still painted, so the fifth card sat
   * in that 40px and showed as a sliver past the four. Taking the gutter out
   * of the width instead makes the border box exactly four cards and three
   * gaps wide, and overflow-x then cuts the next card off cleanly.
   *
   * The arithmetic is unchanged: this is the same content width the padded box
   * resolved to at every size, so the cards keep the dimensions they had. */
  width: calc(100% - 2 * var(--zouma-quotes-gutter));
  max-width: calc(1360px - 2 * var(--zouma-quotes-gutter));
  margin-inline: auto;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.zouma-quotes::-webkit-scrollbar {
  display: none;
}

.zouma-quotes__track {
  display: flex;
  gap: var(--zouma-gap);
  align-items: stretch;
}

.zouma-quote {
  display: flex;
  flex: 0 0 clamp(17.5rem, calc(29.2 * var(--zouma-vw)), 26.25rem);
  flex: 0 0
    calc(
      (100cqi - (var(--zouma-quotes-cols) - 1) * var(--zouma-gap)) /
        var(--zouma-quotes-cols)
    );
  flex-direction: column;
  align-items: flex-start;
  margin: 0;
  padding: 24px;
  background: var(--zouma-teal-deep);
  border-radius: 14px;
  scroll-snap-align: start;
}

.zouma-quote__text {
  margin: 0;
  padding: 0;
  border: 0;
  color: rgba(255, 255, 255, 0.92);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.875rem, 0.78rem + calc(0.28 * var(--zouma-vw)), 1rem);
  font-style: normal;
  font-weight: 400;
  line-height: 1.7;
}

/* The attribution and the logo are pinned to the foot of the card, so the
 * badges line up across the rail however long the quotes run. */
.zouma-quote__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 20px;
}

.zouma-quote__name {
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: clamp(
    0.8125rem,
    0.76rem + calc(0.26 * var(--zouma-vw)),
    0.9375rem
  );
  font-weight: 700;
  line-height: 1.5;
}

.zouma-quote__role {
  color: rgba(255, 255, 255, 0.66);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.75rem, 0.7rem + calc(0.19 * var(--zouma-vw)), 0.8125rem);
  font-weight: 400;
  line-height: 1.5;
}

.zouma-quote__sector {
  margin-top: 6px;
  color: var(--zouma-cyan);
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.3;
  text-transform: uppercase;
}

/* Client logos come in every colour there is. Knocking them back to a flat
 * light grey is what lets four of them sit in a row without one shouting. */
/* The mark sits in an outlined badge rather than directly on the card.
 *
 * A set box rather than one that shrink-wraps the artwork: the four marks are
 * 45 to 107 wide and 16 to 20 tall, so wrapping them gave four badges of four
 * different sizes. Fixed here, they line up down the rail whatever shape the
 * file is, and the mark is contained inside — never stretched, never cropped.
 * max-width keeps it inside a narrow card rather than pushing the card wider. */
.zouma-quote__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 136px;
  max-width: 100%;
  height: 52px;
  padding: 10px 14px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 8px;
  margin-top: 26px;
  /* Floor for the gap down to the result box. The box takes the slack with
	 * margin-top:auto, so this is what stops the two touching on the card that
	 * sets the row height. */
  margin-bottom: 30px;
}

/* Never larger than the file itself.
 *
 * height: 100% pinned every mark to the 30px row, and the partner artwork is
 * 92x20 — so each one was being blown up about a fifth past its own pixels and
 * arriving soft, worst on the marks with fine lettering. Bounded instead of
 * pinned: the box keeps its 30px so the row height never moves, and a logo
 * draws at its natural size unless it is bigger than the space, in which case
 * it shrinks to fit. */
.zouma-quote__logo img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 100%;
  object-fit: contain;
  object-position: center;
  /* Lifted off the dark card rather than tinted: the files are dark artwork on
	 * transparency, so brightness is what makes them visible at all here. */
  filter: grayscale(1) brightness(2.4) contrast(0.5);
  opacity: 0.62;
}

/* Another dark surface, so the vector logos need nothing doing to them — the
 * brightness pass above exists only to rescue the dark rasters. */
.zouma-quote__logo img.is-vector {
  filter: none;
  opacity: 0.78;
}

/* The raster the default pass cannot rescue: fine-lined at 92x20, so the
 * downscale leaves it mostly part-transparent anti-aliasing — what it is short
 * of is coverage, not brightness. The row default runs contrast(0.5) over it,
 * flattening the little contrast it has left, and 0.62 opacity finishes the
 * job: on the dark card it arrives as a grey ghost while every other logo
 * reads solid.
 *
 * Same remedy the trust strip applies, mirrored for a dark ground: knock it
 * flat, invert it to white rather than black, and put the eaten alpha back
 * with a single hairline shadow. One shadow, not two — a second overshoots and
 * starts reading as a bolder logo than the brand's own.
 *
 * Nothing carries this class as it stands — zouma_faint_logos() is empty since
 * incorporatewear became a vector. Kept as the other half of that list. */
.zouma-quote__logo img.is-faint-art {
  filter: brightness(0) invert(1) drop-shadow(0 0 0.35px rgba(255, 255, 255, 1));
  opacity: 0.92;
}
/* Already light, so nothing to rescue — see zouma_light_logos(). */
.zouma-quote__logo img.is-light-art {
  filter: none;
  opacity: 0.92;
}

/* Result box -------------------------------------------------------------- */

/* The value reads across, not down: figure on the left, what it means stacked
 * beside it. At this card width a centred column made the badge taller than
 * the logo above it and threw the row out. */
.zouma-quote__stat {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 70px;
  margin-top: auto;
  padding: 0 10px 0 16px;
  background: var(--zouma-blue);
  border-radius: 10px;
  color: #fff;
}

.zouma-quote__stat-value {
  margin: 0;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.375rem, 1rem + calc(1.28 * var(--zouma-vw)), 1.9375rem);
  font-weight: 700;
  line-height: 1.1;
  white-space: nowrap;
}

.zouma-quote__stat-value span {
  font-size: 0.72em;
}

.zouma-quote__stat-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.zouma-quote__stat-label {
  margin: 0;
  font-family: var(--zouma-font-body);
  font-size: clamp(0.75rem, 0.7rem + calc(0.19 * var(--zouma-vw)), 0.8125rem);
  font-weight: 400;
  line-height: 1.3;
}

.zouma-quote__stat-note {
  margin: 2px 0 0;
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1.3;
  text-transform: uppercase;
  opacity: 0.72;
}

/* Arrows ------------------------------------------------------------------ */

.zouma-quotes__nav {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-top: clamp(1.75rem, calc(3.5 * var(--zouma-vw)), 2.75rem);
}

.zouma-quotes__arrow {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  background: transparent;
  color: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.75);
  border-radius: 8px;
  cursor: pointer;
  transition:
    background var(--zouma-transition),
    border-color var(--zouma-transition),
    color var(--zouma-transition),
    opacity var(--zouma-transition);
}

.zouma-quotes__arrow:hover:not(:disabled) {
  background: var(--zouma-blue);
  border-color: var(--zouma-blue);
  color: #fff;
  transform: none;
}

.zouma-quotes__arrow:disabled {
  opacity: 0.35;
  cursor: default;
}

/* Then two, then one — the card has a floor below which the quote stops being
 * readable. The 1100px step that used to take four down to three is gone with
 * the four; three is where the rail now starts. */
@media (max-width: 820px) {
  .zouma-quotes {
    --zouma-quotes-cols: 2;
  }
}

@media (max-width: 560px) {
  .zouma-quotes {
    --zouma-quotes-cols: 1;
  }
}

/* =========================================================================
 * 12 · Careers.
 *
 *   Section  #FFF · 120px padding · container 1280, two columns 96px apart
 *   Left     470px — eyebrow + Albert Sans 700 · 30/39
 *   Right    714px — Poppins 400 · 14/21 · #121212, then an outline button
 *            24px below
 * ====================================================================== */

/* Opted out of the site-wide full-screen floor (see `main > section` in this
 * file). The band is an eyebrow, a heading, a paragraph and a button — 179px
 * of content — so a viewport-height floor left about 900px of empty white on
 * a 1080 screen. Its own padding sets the height instead.
 *
 * Both properties are needed: min-height undoes the floor, display undoes the
 * centring grid that came with it and puts the section back to block flow. */
.zouma-careers {
  min-height: auto;
  display: block;
  padding-block: 120px;
  background: #fff;
}

.zouma-careers__inner {
  display: grid;
  /* The copy takes the row; the button sits at the end of it.
   *
   * This was 470fr | 714fr with the heading alone on the left, which put a
   * 48px heading in a 470px column and broke it over three lines. The design
   * runs the eyebrow, heading and copy across the width and leaves only the
   * button beside them, so the first column takes what is left and the second
   * is sized by the button. */
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 48px;
  align-items: center;
  max-width: calc(1280px + 2 * clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem));
}

.zouma-careers__intro {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.zouma-careers .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-careers .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-careers__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-careers__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
}

/* The design keeps this copy at full text colour, not the muted grey. */
.zouma-careers__text {
  /* Two lines at the design's width. */
  max-width: 62ch;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
}

@media (max-width: 900px) {
  .zouma-careers {
    padding-block: clamp(3rem, calc(9 * var(--zouma-vw)), 6rem);
  }

  .zouma-careers__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }
}

/* =========================================================================
 * 13 · Knowledge Hub / The ZOUMA Blog.
 *
 *   Section  #E1EDF9 · 120px padding · container 1280, 40px above the grid
 *   Head     1028px copy block left, outline button right (64px gap)
 *   Cards    308×443 · #FFF · 8px radius · image 308×210 · 16px between
 *   Body     24/16 padding · 16px gaps
 *   Badge    day Albert Sans 700 · 32px, month 10/600 uppercase, over the image
 * ====================================================================== */

.zouma-blog {
  padding-block: 120px;
  background: var(--zouma-blue-pale);
}

.zouma-blog__head {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(24px, calc(3 * var(--zouma-vw)), 64px);
  max-width: 1280px;
  margin: 0 auto 40px;
}

.zouma-blog__intro {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.zouma-blog .zouma-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.333;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-blog .zouma-eyebrow .zouma-icon--spark {
  color: var(--zouma-cyan);
}

.zouma-blog__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.35rem, 1rem + calc(1.2 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
}

.zouma-blog__lede {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
}

.zouma-blog__head .zouma-btn--outline {
  flex: 0 0 auto;
}

/* Cards ------------------------------------------------------------------ */

.zouma-blog__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  max-width: 1280px;
  margin: 0 auto;
}

.zouma-post {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
  border: 0;
  border-radius: 8px;
}

.zouma-post:hover {
  transform: none;
  box-shadow: none;
}

.zouma-post__media {
  position: relative;
  display: block;
  aspect-ratio: 308 / 210;
  overflow: hidden;
  background: var(--zouma-teal);
}

.zouma-post__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Date badge: a dark panel let into the top-left corner of the artwork.
 *
 * Flush to both edges rather than floating inset, so it reads as a corner cut
 * out of the image. The top-left radius matches the card's own 8px — anything
 * else leaves a sliver of photo showing in the curve — and the bottom-right is
 * rounded to turn the panel back into the picture. */
.zouma-post__date {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 20px 16px;
  background: rgba(7, 11, 13, 0.92);
  border-radius: 8px 0 14px 0;
  color: #fff;
}

.zouma-post__day {
  font-family: var(--zouma-font-heading);
  /* The number carries the badge, so it is set large and tight — the panel
	 * takes its size from this rather than from a fixed width. */
  font-size: clamp(2.125rem, 1.6rem + calc(1.6 * var(--zouma-vw)), 2.75rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.01em;
}

.zouma-post__month {
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}

.zouma-post__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 16px;
  padding: 24px 16px;
}

/* "HUMAN + AI · 6 MIN READ" */
.zouma-post__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.zouma-post__meta span + span::before {
  content: "·";
  margin-right: 6px;
}

.zouma-post__title {
  margin: 0;
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
}

.zouma-post__title a {
  color: var(--zouma-color-text);
  text-decoration: none;
  /* Two lines, then ellipsis — the design truncates rather than reflowing. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.zouma-post__title a:hover {
  color: var(--zouma-blue);
}

.zouma-post__excerpt {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.zouma-post__link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: auto;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-weight: 600;
  text-decoration: none;
}

.zouma-post__link .zouma-icon {
  transition: transform var(--zouma-transition);
}

.zouma-post__link:hover .zouma-icon {
  transform: translateX(3px);
}

@media (max-width: 1080px) {
  .zouma-blog__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 780px) {
  .zouma-blog {
    padding-block: clamp(3rem, calc(9 * var(--zouma-vw)), 6rem);
  }

  .zouma-blog__head {
    flex-wrap: wrap;
  }

  .zouma-blog__intro {
    flex-basis: 100%;
  }
}

@media (max-width: 520px) {
  .zouma-blog__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* =========================================================================
 * Footer — "Section / Footer".
 *
 *   #121212 · 1280 container · 64px top · rules in #06394E
 *   Columns  256 / 256 / 256 / 440, 24px gaps
 *   Heading  Albert Sans 700 · 30/39 · #FFF
 *   Links    Poppins 400 · 14/21 · #5B6770
 *   Calendar 440×438 · #042634 · 1px #06394E · 8px radius · 24px padding
 * ====================================================================== */

.zouma-footer {
  position: relative;
  padding-block: 64px 0;
  background: var(--zouma-dark);
  color: #fff;
  overflow: hidden;
}

/* Blue wash across the bottom edge. */
.zouma-footer__glow {
  position: absolute;
  left: 50%;
  bottom: -420px;
  width: min(1600px, 140vw);
  height: 620px;
  transform: translateX(-50%);
  background: radial-gradient(
    closest-side,
    rgba(14, 133, 182, 0.55),
    rgba(14, 133, 182, 0) 70%
  );
  pointer-events: none;
}

.zouma-footer__inner {
  position: relative;
  max-width: calc(1280px + 2 * clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem));
}

.zouma-footer__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 40px;
  border-bottom: 1px solid var(--zouma-teal-deep);
}

.zouma-footer__heading {
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.4 * var(--zouma-vw)), 1.875rem);
  font-weight: 700;
  line-height: 1.3;
}

/* Columns ----------------------------------------------------------------- */

.zouma-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 256fr) minmax(0, 256fr) minmax(
      0,
      256fr
    ) minmax(0, 440fr);
  gap: 24px;
  padding-block: 40px;
}

/* The booking panel holds the wide last track whatever precedes it.
 *
 * The four tracks are offices, two link columns and the 440fr panel, and the
 * children used to fill them in source order. Switching a link column off in
 * Site Options leaves three children, so the panel slid up into a 256fr track
 * and the calendar rendered at 256px instead of 440px — narrow enough that the
 * dates crowded.
 *
 * -2 / -1 is the last track counted from the end, so the panel stays put with
 * one link column or two, and the vacated track is simply left empty. */
.zouma-booking {
  grid-column: -2 / -1;
}

.zouma-footer__offices {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.zouma-office__label {
  margin: 0 0 4px;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
}

.zouma-office__address,
.zouma-office__link {
  display: block;
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-style: normal;
  font-weight: 400;
  line-height: 1.5;
  text-decoration: none;
}

.zouma-office__link:hover {
  color: #fff;
}

.zouma-footer__col {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.zouma-footer__group h3 {
  margin: 0 0 12px;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
}

.zouma-footer__group ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.zouma-footer__group li + li {
  margin-top: 8px;
}

.zouma-footer__group a {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
  text-decoration: none;
}

.zouma-footer__group a:hover {
  color: #fff;
}

/* Socials ----------------------------------------------------------------- */

.zouma-socials {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}

.zouma-socials a {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--zouma-teal-deep);
  border-radius: 50%;
  transition:
    background var(--zouma-transition),
    border-color var(--zouma-transition);
}

.zouma-socials a:hover {
  background: var(--zouma-blue);
  border-color: var(--zouma-blue);
}

.zouma-socials__icon {
  width: 15px;
  height: 15px;
  background: #fff;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

/* Booking ----------------------------------------------------------------- */

.zouma-booking {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
}

.zouma-booking__title {
  margin: 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
}

.zouma-booking__note {
  color: var(--zouma-color-muted);
  font-weight: 400;
}

.zouma-booking__sub {
  margin: 8px 0 16px;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
}

.zouma-booking__calendly,
.zouma-booking__frame {
  min-width: 320px;
  height: 438px;
  border-radius: 8px;
  overflow: hidden;
}

/* The Microsoft Bookings frame fills the same box the Calendly widget does, so
 * swapping one scheduler for the other moves nothing around it. */
.zouma-booking__frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Placeholder calendar ---------------------------------------------------- */

.zouma-cal {
  padding: 24px;
  background: var(--zouma-teal);
  border: 1px solid var(--zouma-teal-deep);
  border-radius: 8px;
}

.zouma-cal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 16px;
}

.zouma-cal__month {
  margin: 0;
  color: var(--zouma-sky);
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 600;
}

.zouma-cal__next {
  display: grid;
  place-items: center;
  color: var(--zouma-color-muted);
}

.zouma-cal__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  text-align: center;
}

.zouma-cal__wd {
  padding-bottom: 8px;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.zouma-cal__day {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.zouma-cal__day.is-muted {
  color: rgba(255, 255, 255, 0.2);
}

/* Bookable days are ringed, as in the design. */
.zouma-cal__day.is-open {
  border: 1px solid var(--zouma-blue);
  color: #fff;
}

.zouma-cal__zone {
  margin: 16px 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.6875rem;
}

.zouma-cal__cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 12px;
  color: var(--zouma-sky);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
}

/* Bookable dates ---------------------------------------------------------- */

/* The grid only becomes interactive once a scheduler is configured, and its
 * dates are then real buttons. style.css gives every bare button a filled
 * primary background, padding, a radius and a hover that repaints it — all of
 * which has to be undone here or each date turns into a blue pill. The element
 * is named in the selector for specificity: `button.zouma-cal__day` outranks
 * the bare `button`, while `.zouma-cal__day.is-open` still outranks this, so
 * the ringed days keep their ring. */
button.zouma-cal__day {
  width: auto;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 50%;
  font-weight: inherit;
  line-height: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

button.zouma-cal__day:hover,
button.zouma-cal__day:focus-visible {
  background: var(--zouma-blue);
  border-color: var(--zouma-blue);
  color: #fff;
}

button.zouma-cal__day:focus-visible {
  outline: 2px solid var(--zouma-cyan);
  outline-offset: 2px;
}

/* Booking overlay --------------------------------------------------------- */

/* Held on the root element while the panel is up, so the page behind it does
 * not scroll away under the dialog. Removed on close, which matters: a lasting
 * overflow here would turn the root into a scroll container and strand the
 * sticky header. */
.zouma-noscroll,
.zouma-noscroll body {
  overflow: hidden;
}

.zouma-bookdlg {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 3vw, 2.5rem);
  background: rgba(4, 26, 32, 0.72);
  opacity: 0;
  transition: opacity 0.24s ease;
}

/* Outranks the display: grid above, which would otherwise hold a hidden
 * dialog on screen. */
.zouma-bookdlg[hidden] {
  display: none;
}

.zouma-bookdlg.is-open {
  opacity: 1;
}

.zouma-bookdlg__panel {
  display: flex;
  flex-direction: column;
  width: min(920px, 100%);
  height: min(760px, 100%);
  overflow: hidden;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.36);
  transform: translateY(12px);
  transition: transform 0.24s ease;
}

.zouma-bookdlg.is-open .zouma-bookdlg__panel {
  transform: none;
}

.zouma-bookdlg__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--zouma-color-border);
}

.zouma-bookdlg__title {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 1rem;
  font-weight: 600;
}

button.zouma-bookdlg__close {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: none;
  color: var(--zouma-color-muted);
  border: 0;
  border-radius: 50%;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

button.zouma-bookdlg__close:hover {
  background: rgba(18, 18, 18, 0.06);
  color: var(--zouma-color-text);
}

/* The scheduler takes whatever is left under the heading. */
.zouma-bookdlg__frame {
  flex: 1 1 auto;
  width: 100%;
  border: 0;
}

/* Only ever seen when the scheduler refused to be framed — Microsoft's
 * calendar apps send a frame-ancestors policy and the browser honours it,
 * which used to leave a tall blank panel and an error only the console saw. */
.zouma-bookdlg__warn {
  display: none;
  margin: 0;
  padding: 20px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  line-height: 1.5;
  text-align: center;
}

.zouma-bookdlg.is-blocked .zouma-bookdlg__warn {
  display: block;
}

/* The frame is given up on rather than left holding empty height, so the
 * panel shrinks to the message instead of framing a void. */
.zouma-bookdlg.is-blocked .zouma-bookdlg__frame {
  display: none;
}

.zouma-bookdlg.is-blocked .zouma-bookdlg__panel {
  height: auto;
}

/* A scheduler that refuses to be framed leaves a blank panel and no clue.
 * This is the way out of one. */
.zouma-bookdlg__out {
  margin: 0;
  padding: 10px 20px;
  border-top: 1px solid var(--zouma-color-border);
  text-align: center;
}

.zouma-bookdlg__out a {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
}

@media (prefers-reduced-motion: reduce) {
  .zouma-bookdlg,
  .zouma-bookdlg__panel {
    transition: none;
  }
}

/* Booking panel ----------------------------------------------------------- */

/* The panel sizes to its contents; only a framed scheduler needs a fixed
 * height, since an iframe has no intrinsic one to give. */
.zouma-bookdlg__body {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

.zouma-bookdlg.is-frame .zouma-bookdlg__panel {
  height: min(760px, 100%);
}

.zouma-bookdlg.is-frame .zouma-bookdlg__body {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
}

/* Bottom bar -------------------------------------------------------------- */

.zouma-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 40px;
  border-top: 1px solid var(--zouma-teal-deep);
}

.zouma-footer__copy {
  margin: 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  line-height: 1.5;
}

.zouma-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.zouma-footer__legal a {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  text-decoration: none;
}

.zouma-footer__legal a:hover {
  color: #fff;
}

@media (max-width: 1080px) {
  .zouma-footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 40px 24px;
  }

  .zouma-booking {
    grid-column: 1 / -1;
  }
}

@media (max-width: 620px) {
  .zouma-footer__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Social glyphs, applied as masks so they inherit the icon colour. */
.zouma-socials__icon--linkedin {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4.98 3.5a2.5 2.5 0 11-.02 5 2.5 2.5 0 01.02-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-1 1.83-2.05 3.77-2.05 4.03 0 4.78 2.65 4.78 6.1V21h-4v-5.4c0-1.3-.02-2.96-1.8-2.96-1.8 0-2.08 1.4-2.08 2.86V21H9z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4.98 3.5a2.5 2.5 0 11-.02 5 2.5 2.5 0 01.02-5zM3 9h4v12H3zM9 9h3.8v1.7h.05c.53-1 1.83-2.05 3.77-2.05 4.03 0 4.78 2.65 4.78 6.1V21h-4v-5.4c0-1.3-.02-2.96-1.8-2.96-1.8 0-2.08 1.4-2.08 2.86V21H9z'/%3E%3C/svg%3E");
}

.zouma-socials__icon--x {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.9 2H22l-7.1 8.1L23.2 22h-6.6l-5.2-6.8L5.5 22H2.4l7.6-8.7L1.2 2h6.8l4.7 6.2zm-1.1 18h1.7L7.3 3.7H5.5z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18.9 2H22l-7.1 8.1L23.2 22h-6.6l-5.2-6.8L5.5 22H2.4l7.6-8.7L1.2 2h6.8l4.7 6.2zm-1.1 18h1.7L7.3 3.7H5.5z'/%3E%3C/svg%3E");
}

.zouma-socials__icon--facebook {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M13.5 22v-8h2.7l.4-3.1h-3.1V8.9c0-.9.25-1.5 1.55-1.5h1.65V4.6c-.3-.04-1.3-.13-2.45-.13-2.42 0-4.08 1.48-4.08 4.2v2.23H7.5V14h2.67v8z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M13.5 22v-8h2.7l.4-3.1h-3.1V8.9c0-.9.25-1.5 1.55-1.5h1.65V4.6c-.3-.04-1.3-.13-2.45-.13-2.42 0-4.08 1.48-4.08 4.2v2.23H7.5V14h2.67v8z'/%3E%3C/svg%3E");
}

.zouma-socials__icon--instagram {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.2c3.2 0 3.6 0 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.25.07 1.62.07 4.81s0 3.56-.07 4.81c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.25.06-1.62.07-4.85.07s-3.6 0-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.8 3.8 0 01-1.38-.9 3.8 3.8 0 01-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.2 15.56 2.2 15.19 2.2 12s0-3.56.07-4.81c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.44 2.2 8.8 2.2 12 2.2zm0 1.8c-3.14 0-3.5.01-4.73.07-.9.04-1.39.19-1.71.32-.43.17-.74.37-1.06.69-.32.32-.52.63-.69 1.06-.13.32-.28.81-.32 1.71C3.43 8.87 3.42 9.23 3.42 12s.01 3.13.07 4.35c.04.9.19 1.39.32 1.71.17.43.37.74.69 1.06.32.32.63.52 1.06.69.32.13.81.28 1.71.32 1.23.06 1.59.07 4.73.07s3.5-.01 4.73-.07c.9-.04 1.39-.19 1.71-.32.43-.17.74-.37 1.06-.69.32-.32.52-.63.69-1.06.13-.32.28-.81.32-1.71.06-1.22.07-1.58.07-4.35s-.01-3.13-.07-4.35c-.04-.9-.19-1.39-.32-1.71a2.9 2.9 0 00-.69-1.06 2.9 2.9 0 00-1.06-.69c-.32-.13-.81-.28-1.71-.32-1.23-.06-1.59-.07-4.73-.07zm0 3.06a4.94 4.94 0 110 9.88 4.94 4.94 0 010-9.88zm0 8.15a3.21 3.21 0 100-6.42 3.21 3.21 0 000 6.42zm6.29-8.35a1.15 1.15 0 11-2.3 0 1.15 1.15 0 012.3 0z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.2c3.2 0 3.6 0 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.25.07 1.62.07 4.81s0 3.56-.07 4.81c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.25.06-1.62.07-4.85.07s-3.6 0-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.8 3.8 0 01-1.38-.9 3.8 3.8 0 01-.9-1.38c-.16-.42-.36-1.06-.41-2.23C2.2 15.56 2.2 15.19 2.2 12s0-3.56.07-4.81c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.44 2.2 8.8 2.2 12 2.2zm0 1.8c-3.14 0-3.5.01-4.73.07-.9.04-1.39.19-1.71.32-.43.17-.74.37-1.06.69-.32.32-.52.63-.69 1.06-.13.32-.28.81-.32 1.71C3.43 8.87 3.42 9.23 3.42 12s.01 3.13.07 4.35c.04.9.19 1.39.32 1.71.17.43.37.74.69 1.06.32.32.63.52 1.06.69.32.13.81.28 1.71.32 1.23.06 1.59.07 4.73.07s3.5-.01 4.73-.07c.9-.04 1.39-.19 1.71-.32.43-.17.74-.37 1.06-.69.32-.32.52-.63.69-1.06.13-.32.28-.81.32-1.71.06-1.22.07-1.58.07-4.35s-.01-3.13-.07-4.35c-.04-.9-.19-1.39-.32-1.71a2.9 2.9 0 00-.69-1.06 2.9 2.9 0 00-1.06-.69c-.32-.13-.81-.28-1.71-.32-1.23-.06-1.59-.07-4.73-.07zm0 3.06a4.94 4.94 0 110 9.88 4.94 4.94 0 010-9.88zm0 8.15a3.21 3.21 0 100-6.42 3.21 3.21 0 000 6.42zm6.29-8.35a1.15 1.15 0 11-2.3 0 1.15 1.15 0 012.3 0z'/%3E%3C/svg%3E");
}

.zouma-socials__icon--youtube {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23 12s0-3.4-.43-5.03a2.6 2.6 0 00-1.83-1.84C19.11 4.7 12 4.7 12 4.7s-7.11 0-8.74.43a2.6 2.6 0 00-1.83 1.84C1 8.6 1 12 1 12s0 3.4.43 5.03c.24.9.94 1.6 1.83 1.84 1.63.43 8.74.43 8.74.43s7.11 0 8.74-.43a2.6 2.6 0 001.83-1.84C23 15.4 23 12 23 12zM9.75 15.02V8.98L15.5 12z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M23 12s0-3.4-.43-5.03a2.6 2.6 0 00-1.83-1.84C19.11 4.7 12 4.7 12 4.7s-7.11 0-8.74.43a2.6 2.6 0 00-1.83 1.84C1 8.6 1 12 1 12s0 3.4.43 5.03c.24.9.94 1.6 1.83 1.84 1.63.43 8.74.43 8.74.43s7.11 0 8.74-.43a2.6 2.6 0 001.83-1.84C23 15.4 23 12 23 12zM9.75 15.02V8.98L15.5 12z'/%3E%3C/svg%3E");
}

/* Outline button for dark backgrounds: transparent, 1.5px #E4E9EE, white
 * text. Used by the footer's "Book a Free Call". */
.zouma-btn--outline-light {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: transparent;
  color: #fff;
  border: 1.5px solid #e4e9ee;
  border-radius: 4px;
  font-family: var(--zouma-font-body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.625;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background var(--zouma-transition),
    color var(--zouma-transition),
    border-color var(--zouma-transition);
}

.zouma-btn--outline-light:hover {
  background: #fff;
  color: var(--zouma-dark);
  border-color: #fff;
  transform: none;
}

.zouma-btn--outline-light .zouma-icon {
  transition: transform var(--zouma-transition);
}

.zouma-btn--outline-light:hover .zouma-icon {
  transform: translateX(3px);
}

/* =========================================================================
 * Hero motion.
 *
 *   Entrance   heading lines rise out of a mask, then the sub-heading,
 *              buttons, trust strip and info bar follow on a stagger.
 *   Glow       the colour fields drift on their own and lean towards the
 *              pointer; JS writes the transform, CSS owns the look.
 *
 * Everything here is disabled under prefers-reduced-motion.
 * ====================================================================== */

.zouma-hero__title {
  /* The mask needs a block box per line. */
  display: block;
}

.zouma-hero__line {
  display: block;
  overflow: hidden;
}

.zouma-hero__line > span {
  display: block;
  transform: translateY(110%);
  will-change: transform;
  animation: zouma-line-up 1s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 110ms);
}

@keyframes zouma-line-up {
  from {
    transform: translateY(110%);
  }
  to {
    transform: translateY(0);
  }
}

.zouma-reveal {
  opacity: 0;
  animation: zouma-fade-up 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 110ms + 120ms);
}

@keyframes zouma-fade-up {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* The blobs are moved by JS; keep them on their own layer. */
.zouma-hero__blob {
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .zouma-hero__line > span,
  .zouma-reveal {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* The dot grid is panned via background-position by main.js, so it needs its
 * own compositor layer and must not fight a CSS transform. */
.zouma-hero__dots {
  will-change: background-position;
}

/* =========================================================================
 * Page motion — GSAP entrances.
 *
 * assets/js/header-motion.js settles the glass bar and brings its contents in
 * on it, on every page. assets/js/hero-motion.js runs the hero entrance once
 * on load — the glow field fades up, then the heading, the sub-heading, the
 * buttons and the trust and info strips — and leaves two infinite timelines
 * drifting behind it.
 *
 * None of these rules change a settled hero: they hand ownership over for the
 * length of the entrance and describe the state the module hands back to. And
 * none of them apply unless the flag printed in the head has added
 * .zouma-gsap, which it does not do under prefers-reduced-motion and which a
 * timeout removes again if the module never reports in — so the CSS entrance
 * above stays the fallback in every case.
 * ====================================================================== */

/* Two owners write to the blob transform: main.js pans the field with the
 * pointer, and the shape loop floats and turns each blob on its own clock.
 * Composing them from custom properties keeps both, where a shared transform
 * property would have had the last writer win on every frame. */
.zouma-hero__blob {
  --zouma-blob-x: 0px;
  --zouma-blob-y: 0px;
  --zouma-shape-x: 0px;
  --zouma-shape-y: 0px;
  --zouma-shape-r: 0deg;

  transform: translate3d(var(--zouma-blob-x), var(--zouma-blob-y), 0)
    translate3d(var(--zouma-shape-x), var(--zouma-shape-y), 0)
    rotate(var(--zouma-shape-r));
}

/* GSAP owns the entrance, so the CSS one stands down — and these are the
 * values the module clears back to when the sequence has settled. */
.zouma-gsap .zouma-hero__line > span,
.zouma-gsap .zouma-hero .zouma-reveal {
  animation: none;
  opacity: 1;
  transform: none;
}

/* The heading lines come in blurred, and the mask that carried the CSS
 * entrance would cut that blur off at the line box. */
.zouma-gsap .zouma-hero__line {
  overflow: visible;
}

/* Held between the flag being printed in the head and the modules setting
 * their own from-states, so nothing can flash in ahead of its entrance.
 *
 * The header bar is not in this list on purpose: it slides rather than fades,
 * because it carries a backdrop-filter that opacity below 1 would blank for
 * the length of the animation. Only its contents are held. */
.zouma-gsap-pending .zouma-header__logo,
.zouma-gsap-pending .zouma-nav__list > li,
.zouma-gsap-pending .zouma-lang,
.zouma-gsap-pending .zouma-header__cta,
.zouma-gsap-pending .zouma-nav-toggle,
.zouma-gsap-pending .zouma-hero__bg,
.zouma-gsap-pending .zouma-hero__line > span,
.zouma-gsap-pending .zouma-hero .zouma-reveal {
  opacity: 0;
}

/* =========================================================================
 * Intro statement — typewriter reveal.
 *
 * Characters are wrapped by main.js and revealed on a timer. Each one fades
 * over a short transition rather than snapping, which reads as smooth typing
 * without the whole paragraph animating at once. Whitespace is left as plain
 * text, so the layout is settled before the first character appears and no
 * reflow happens mid-animation.
 * ====================================================================== */

/* =========================================================================
 * 03 · Stats grid — draw-on reveal
 *
 * A single dot at the centre, which expands into the grid when the section
 * scrolls into view: the seed lands, the rules unfold outward from it, the
 * intersections drop in behind them, and the figures bloom out last, drifting
 * from the centre to their places.
 *
 * Everything here animates transform and opacity and nothing else, which is
 * what lets the browser run the whole reveal on the compositor at the screen's
 * own refresh rate. No width, no height, no top/left, no filter, no box-shadow
 * — any one of those would drag it back onto the main thread and cost frames.
 *
 * The stagger is a radial distance from the centre, measured by main.js off the
 * real boxes and written to each element as a --d delay and a --t duration.
 * That is the whole of the JavaScript's involvement: it writes two numbers per
 * element, once, and the animation itself is pure CSS.
 *
 * Nothing applies until main.js adds is-armed, so with the option off, under
 * reduced motion, or with no JavaScript at all, the grid is simply there.
 * ====================================================================== */

.zouma-statgrid__seed {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  /* Centred by margin rather than translate, so transform is free to carry
	 * the scale on its own. */
  margin: -5px 0 0 -5px;
  background: var(--zouma-blue);
  border-radius: 50%;
  opacity: 0;
}

/* The ripple the dot throws off as it goes. A sibling rather than a child of
 * the seed, so it travels on its own curve instead of compounding with the
 * dot's. Drawn as a gradient rather than a border because it is sized by
 * transform: a scaled border would come out twenty-odd times too thick, where
 * a gradient band keeps its proportions the whole way out. */
.zouma-statgrid__ripple {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    transparent 0 56%,
    var(--zouma-rule) 64% 72%,
    transparent 80%
  );
  opacity: 0;
}

/* Both run one keyframed pass rather than a transition, because they have a
 * middle: in, hold, then out again. --t is the pair's shared slice of the run,
 * so they stay in step with the rules whatever the grid measures. */
.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__seed,
.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__ripple {
  animation-duration: var(--t, 680ms);
  animation-delay: var(--d, 0ms);
  animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  animation-fill-mode: both;
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__seed {
  animation-name: zouma-stat-seed;
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__ripple {
  animation-name: zouma-stat-ripple;
}

/* The dot only swells a little on its way out — the ripple does the
 * travelling, so nothing ever sits over the middle figure as a blob. */
@keyframes zouma-stat-seed {
  0% {
    opacity: 0;
    transform: scale(0);
  }
  25% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(4);
  }
}

/* Capped around 500px across: clears the frame top and bottom without reaching
 * past the section or forcing a sideways scrollbar. */
@keyframes zouma-stat-ripple {
  0% {
    opacity: 0;
    transform: scale(0);
  }
  25% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(25);
  }
}

/* IMPORTANT — the from-poses below carry no transition of their own, and the
 * transitions live on the is-in rules instead.
 *
 * Arming the section is a style change like any other. These elements are in
 * the page from the start, so if the collapsed pose arrived with a transition
 * already attached, the browser would animate *into* it: the grid would spend
 * the delay sitting there fully drawn and then visibly close before it opened.
 * Introducing the transition alongside the target value animates the one
 * change that should be animated, and the collapse happens instantly.
 *
 * (The heading words escape this by being built in JavaScript — a brand new
 * element has no previous style to transition from — but relying on that would
 * be a trap for whoever edits this next.)
 *
 * Verticals unfold from the horizontal centre line and horizontals from the
 * vertical one, so the frame opens out of the middle rather than sweeping in
 * from an edge. */
.zouma-statgrid__frame.is-armed .zouma-statgrid__vline,
.zouma-statgrid__frame.is-armed .zouma-statgrid__hline {
  transform-origin: 50% 50%;
}

.zouma-statgrid__frame.is-armed .zouma-statgrid__vline {
  transform: scaleY(0);
}

.zouma-statgrid__frame.is-armed .zouma-statgrid__hline {
  transform: scaleX(0);
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__vline,
.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__hline {
  transition: transform var(--t, 420ms) cubic-bezier(0.22, 1, 0.36, 1)
    var(--d, 0ms);
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__vline {
  transform: scaleY(1);
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__hline {
  transform: scaleX(1);
}

/* A little overshoot on the intersections, so they land rather than fade up.
 * The fade is kept shorter than the travel — a dot that is still translucent
 * while it is settling reads as a smudge rather than a point. */
.zouma-statgrid__frame.is-armed .zouma-statgrid__dot {
  opacity: 0;
  transform: scale(0);
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__dot {
  opacity: 1;
  transform: scale(1);
  transition:
    opacity calc(var(--t, 300ms) * 0.6) linear var(--d, 0ms),
    transform var(--t, 300ms) cubic-bezier(0.34, 1.56, 0.64, 1) var(--d, 0ms);
}

/* The figures start gathered in towards the centre — --tx/--ty are each cell's
 * own offset to it, measured by main.js — and are carried out to their places
 * as they fade up. translate3d rather than translate so the pose is a
 * compositor one from the first frame, with no promotion mid-animation. */
.zouma-statgrid__frame.is-armed .zouma-statgrid__cell {
  opacity: 0;
  transform: translate3d(var(--tx, 0px), var(--ty, 0px), 0) scale(0.92);
}

.zouma-statgrid__frame.is-armed.is-in .zouma-statgrid__cell {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
  transition:
    opacity var(--t, 490ms) ease-out var(--d, 0ms),
    transform var(--t, 490ms) cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms);
}

/* Promoted for the length of the run only. Held past the end it would leave
 * the figures rasterised at their animated size instead of crisp at their
 * real one, and pin layers the page has no further use for. */
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__vline,
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__hline,
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__dot,
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__cell,
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__seed,
.zouma-statgrid__frame.is-armed.is-live .zouma-statgrid__ripple {
  will-change: opacity, transform;
}

/* =========================================================================
 * 03 · Stats heading — masked word rise
 *
 * The eyebrow lifts in and its spark twists into place, then the heading
 * arrives a word at a time, each rising from behind its own baseline. The clip
 * is the point: the words come up out of the line rather than fading in over
 * it, which is what makes it read as typeset rather than animated.
 *
 * main.js wraps each word in a clipping box around a moving inner span and
 * writes the per-word delay as --d. Transform and opacity only, so it runs on
 * the compositor like the grid does.
 *
 * Nothing applies until is-armed, so with no JavaScript or under reduced
 * motion the heading is simply the heading.
 * ====================================================================== */

.zouma-stats__head.is-armed .zouma-stats__word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* Descenders would be clipped by the box that does the masking. The
	 * padding gives them room and the margin takes it straight back off the
	 * layout, so the heading keeps the line height it was designed with. */
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}

/* As in the grid above, the transitions belong on the is-in rules: the eyebrow
 * and its spark are in the page from the start, and would otherwise animate
 * *out* the moment the section was armed. */
.zouma-stats__head.is-armed .zouma-stats__word > span {
  display: inline-block;
  transform: translate3d(0, 110%, 0);
}

/* Only for the length of the run — a heading is a dozen or more spans, and
 * they should not each keep a compositor layer for the rest of the visit. */
.zouma-stats__head.is-armed.is-live .zouma-stats__word > span,
.zouma-stats__head.is-armed.is-live .zouma-eyebrow,
.zouma-stats__head.is-armed.is-live .zouma-eyebrow .zouma-icon--spark {
  will-change: transform;
}

.zouma-stats__head.is-armed.is-in .zouma-stats__word > span {
  transform: translate3d(0, 0, 0);
  transition: transform 780ms cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms);
}

.zouma-stats__head.is-armed .zouma-eyebrow {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
}

.zouma-stats__head.is-armed.is-in .zouma-eyebrow {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition:
    opacity 560ms ease-out,
    transform 560ms cubic-bezier(0.22, 1, 0.36, 1);
}

/* The spark lands after the eyebrow has started moving, with enough overshoot
 * to read as a flourish rather than a fade. */
.zouma-stats__head.is-armed .zouma-eyebrow .zouma-icon--spark {
  transform: scale(0) rotate(-140deg);
}

.zouma-stats__head.is-armed.is-in .zouma-eyebrow .zouma-icon--spark {
  transform: scale(1) rotate(0deg);
  transition: transform 700ms cubic-bezier(0.34, 1.56, 0.64, 1) 180ms;
}

/* =========================================================================
 * 03 · Stats figures — count up
 *
 * main.js wraps each run of digits in a figure and counts it up from zero as
 * that cell arrives. Only the two rules below are needed here; the counting
 * itself is text, which is the one thing in this section that cannot be done
 * on the compositor.
 * ====================================================================== */

/* The value rule sets every span smaller, for the separator in "24x6". The
 * counters are spans too, and are not that. */
.zouma-statgrid__value .zouma-stat-count {
  font-size: 1em;
}

/* Proportional numerals put a 1 at half the width of a 7, so a number counting
 * up shuffles sideways the whole way. Fixed-width figures for the climb only —
 * the class comes off at the end and the finished figure is set in the face
 * the design asked for. */
.zouma-statgrid__value.is-counting .zouma-stat-count {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* =========================================================================
 * Scroll entrances — the shared effect vocabulary
 *
 * Sections 04 onwards ask for one of these by name in the markup
 * (data-zouma-reveal) and main.js decides when each piece goes. The effects
 * are deliberately few: a page where every section arrives differently reads
 * as a demo reel, where one where they share a language reads as designed.
 *
 * As with the stats grid, the from-poses carry no transition and the
 * transition is introduced with the target value on .is-in. These elements are
 * in the page from the start, so a transition attached to the from-pose would
 * animate them *out* the moment the section was armed.
 *
 * Transform and opacity only, so every one of them runs on the compositor.
 * Nothing applies until is-enter, so with no JavaScript or under reduced
 * motion the page is simply the page.
 * ====================================================================== */

.is-enter {
  opacity: 0;

  /* Not optional. Some of the things being revealed declare a transition of
	 * their own — .zouma-btn animates transform for its hover lift — and that
	 * would apply to the from-pose too, so arming a section would visibly
	 * slide its buttons down into place before the reveal slid them back. The
	 * posed state must be instant; .is-in below is more specific and brings
	 * the transition back for the one change that should animate. */
  transition: none;
}

.is-enter.is-live {
  will-change: opacity, transform;
}

.is-enter.is-in {
  opacity: 1;
  transform: none;
  transition:
    opacity 720ms cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms),
    transform 720ms cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms);
}

/* Rises into place. The workhorse — headings, copy, most card grids. */
.is-enter--up {
  transform: translate3d(0, 30px, 0);
}

/* Comes in from the side. For two-column sections, so the halves arrive
 * towards each other rather than both drifting the same way. */
.is-enter--left {
  transform: translate3d(-40px, 0, 0);
}

.is-enter--right {
  transform: translate3d(40px, 0, 0);
}

/* Settles from slightly small. For callouts and single focal blocks, where a
 * slide would read as arriving from somewhere rather than resolving. */
.is-enter--zoom {
  transform: scale(0.94);
}

/* Lands with a little overshoot. For small, discrete things — a number, an
 * icon — that should feel placed rather than faded up. */
.is-enter--pop {
  transform: scale(0.6);
}

.is-enter--pop.is-in {
  transition:
    opacity 380ms ease-out var(--d, 0ms),
    transform 620ms cubic-bezier(0.34, 1.56, 0.64, 1) var(--d, 0ms);
}

/* Uncovers itself, bottom edge travelling up, with the content easing out of a
 * slight over-scale behind it. For images — a photograph that wipes on reads
 * far better than one that fades. clip-path is a compositor property in every
 * browser that matters, so this stays as cheap as the rest. */
.is-enter--mask {
  transform: scale(1.06);
  clip-path: inset(0 0 100% 0);
  opacity: 1;
}

.is-enter--mask.is-in {
  transform: none;
  clip-path: inset(0 0 0 0);
  transition:
    clip-path 900ms cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms),
    transform 1100ms cubic-bezier(0.22, 1, 0.36, 1) var(--d, 0ms);
}

/* These classes hide real content until the reveal plays, so main.js arms and
 * observes each group in the same step — a group is never left hidden with
 * nothing watching for it. Under reduced motion none of it is applied at all,
 * and this is the backstop for anything already marked up. */
@media (prefers-reduced-motion: reduce) {
  .is-enter {
    opacity: 1;
    transform: none;
    clip-path: none;
    transition: none;
  }
}

/* =========================================================================
 * 02 · Intro statement — typewriter reveal
 *
 * The alternative to the above, used when the scroll reveal is switched off.
 * ====================================================================== */

.zouma-char {
  opacity: 0;
  transition: opacity 60ms linear;
}

.zouma-char.is-in {
  opacity: 1;
}

/* Caret on the character just typed. */
.zouma-char.is-cursor {
  border-right: 2px solid var(--zouma-blue);
  margin-right: -2px;
  animation: zouma-caret 900ms step-end infinite;
}

@keyframes zouma-caret {
  50% {
    border-right-color: transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .zouma-char {
    opacity: 1;
    border-right: 0;
    margin-right: 0;
    animation: none !important;
    transition: none;
  }
}

/* =========================================================================
 * Section heights
 *
 * Every band here used to be floored at one screen tall. The design does not
 * work that way: its sections have their own heights, and they vary a lot —
 * the stats run well past a screen because the six figures stack in a column,
 * while the journey rail and the careers call-to-action are each under half of
 * one. Holding them all to 100vh added roughly 2500px of empty page and, more
 * to the point, flattened the rhythm the design is built on. Sections now take
 * the height their content and padding give them.
 *
 * .zouma-whois no longer keeps a floor either. It had one so the band filled
 * the screen, but on a wide monitor that left the photograph and the logo
 * rail marooned in the middle of a screenful of empty ground. It takes the
 * height of its content now, like the rest.
 * ====================================================================== */
/* .zouma-careers is deliberately not in that list. It is a slim call-to-action
 * band — a heading, a sentence and one button — and every other section here
 * was already 85-90% of a screen, so the floor only nudged them. This one was
 * 370px and more than doubled, leaving roughly 500px of empty white under the
 * button that read as a loading fault rather than as space. It keeps its
 * natural height. */

/* Centring, split by what each section already is.
 *
 * A blanket `display: flex; flex-direction: column` here is wrong and was the
 * first thing I tried: .zouma-instinct is a two-column grid and .zouma-pillars
 * is already a flex row, so forcing a column direction collapsed both of them —
 * the instinct section lost its diagram entirely.
 *
 * These are the sections whose only in-flow child is the .zouma-shell wrapper
 * (any decorative layer they carry is absolutely positioned, so it is out of
 * flow and unaffected). Making them flex columns is safe and centres the
 * wrapper in the extra height. */
.zouma-stats,
.zouma-sun,
.zouma-standards,
.zouma-outcomes,
.zouma-testimonials,
.zouma-blog {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* Grid keeps its columns; align-content centres the row band inside the taller
 * box without touching the track definition. */
.zouma-instinct {
  align-content: center;
}

/* =========================================================================
 * Legal pages — Privacy Policy
 * ====================================================================== */

/* Dark band under the header, the same trick the other inner heroes use: pull
 * up by the header height and put it back as padding, so the bar sits on the
 * dark rather than on the white below it. */
.zouma-legal-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Full screen on any device — the same pair the homepage hero uses.
	 *
	 * min-height rather than height, so a short screen or large type pushes
	 * the section taller instead of clipping the copy. svh after vh because
	 * 100vh on a phone measures the viewport with the browser chrome
	 * retracted, which runs taller than what the visitor can actually see;
	 * vh stays first as the fallback.
	 *
	 * The section is already pulled up under the sticky header, so the
	 * header's height is counted inside this 100. */
  /* Not a full screen on this page. The design gives the legal pages a
	 * compact masthead — an eyebrow, a title and a date — and a screenful of
	 * black above a wall of policy text reads as a loading fault rather than
	 * as space. The floor here is roughly what the design measures. */
  min-height: clamp(15rem, calc(20 * var(--zouma-vw)), 18rem);
  margin-top: calc(-1 * var(--zouma-header-h));
  padding-top: calc(
    var(--zouma-header-h) + clamp(2.5rem, calc(5 * var(--zouma-vw)), 4.5rem)
  );
  padding-bottom: clamp(2.25rem, calc(4.5 * var(--zouma-vw)), 4rem);
  background: #0d0d0d;
  overflow: hidden;
}

/* The cyan lift along the bottom edge, as in the design. */
.zouma-legal-hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 60%;
  background: radial-gradient(
    ellipse 42% 100% at 50% 132%,
    rgba(14, 133, 182, 0.5) 0%,
    rgba(14, 133, 182, 0.14) 45%,
    rgba(14, 133, 182, 0) 78%
  );
  pointer-events: none;
}

.zouma-legal-hero__inner {
  position: relative;
  z-index: 1;
}

.zouma-legal-hero__title {
  margin: 12px 0 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(2rem, 1.3rem + calc(2.2 * var(--zouma-vw)), 3.25rem);
  font-weight: 700;
  line-height: 1.15;
}

.zouma-legal-hero__meta {
  margin: 10px 0 0;
  color: rgba(255, 255, 255, 0.56);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
}

/* Body ------------------------------------------------------------------- */

.zouma-legal {
  padding-block: clamp(2.5rem, calc(5 * var(--zouma-vw)), 4.5rem);
  background: #fff;
}

/* Narrower than .zouma-shell. This is a reading column — the policy is long
 * and unbroken, and at the site's full 1320px measure the lines run past a
 * comfortable length. */
.zouma-legal__shell {
  width: 100%;
  max-width: 980px;
  margin-inline: auto;
  padding-inline: clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
}

.zouma-legal__item {
  margin-bottom: 14px;
  padding: 18px 22px 4px;
  background: #fff;
  border: 1px solid #e6edf4;
  border-radius: 10px;
}

.zouma-legal__item[open] {
  padding-bottom: 18px;
}

/* The default disclosure triangle is replaced by the caret below. */
.zouma-legal__summary {
  display: flex;
  align-items: center;
  gap: 14px;
  cursor: pointer;
  list-style: none;
}

.zouma-legal__summary::-webkit-details-marker {
  display: none;
}

.zouma-legal__num {
  flex: 0 0 auto;
  color: var(--zouma-cyan);
  font-family: var(--zouma-font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1;
}

.zouma-legal__heading {
  flex: 1 1 auto;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.3;
}

.zouma-legal__summary .zouma-icon--caret {
  flex: 0 0 auto;
  color: #8fa3b5;
  transition: transform 220ms ease;
}

/* Points up while open, down while closed — the arrow shows what a click does
 * next, which is the way the design draws it. */
.zouma-legal__item[open] .zouma-legal__summary .zouma-icon--caret {
  transform: rotate(180deg);
}

.zouma-legal__body {
  padding-top: 12px;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.75;
}

.zouma-legal__body p {
  margin: 0 0 10px;
}

.zouma-legal__body p:last-child,
.zouma-legal__body ul:last-child {
  margin-bottom: 0;
}

/* The lists sit closer to their paragraph than they did: the design indents
 * them about two thirds of what was here, so the bullets read as part of the
 * same block rather than as a separate column. */
.zouma-legal__body ul {
  margin: 0 0 10px;
  padding-left: 21px;
  list-style: none;
}

.zouma-legal__body li {
  position: relative;
  /* Line-height stated here rather than inherited, so a bullet that wraps to
	 * two lines keeps the same rhythm as the paragraphs around it. */
  line-height: 1.75;
  margin-bottom: 6px;
}

.zouma-legal__body li:last-child {
  margin-bottom: 0;
}

/* A plain bullet, drawn rather than set as a list-style.
 *
 * The item keeps position: absolute for its mark, which is what gives the
 * hanging indent: the mark is out of flow, so a point that runs to two lines
 * wraps under its own first word instead of under the bullet.
 *
 * currentColor, so the bullet is the same muted grey as the sentence it
 * belongs to and stays subtle. top is in em so it holds its optical centre on
 * the first line whatever the type size. */
.zouma-legal__body li::before {
  content: "";
  position: absolute;
  left: -13px;
  top: 0.72em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}

.zouma-legal__body strong {
  color: var(--zouma-color-text);
  font-weight: 600;
}

.zouma-legal__body a {
  color: var(--zouma-blue);
  text-decoration: underline;
}

/* Closing call to action ------------------------------------------------- */

/* The start-saving band.
 *
 * A section in its own right, not a card inside the policy list — the design
 * runs it edge to edge under the accordion, with the copy on the left and the
 * call to action held out to the right.
 */
.zouma-legal-cta {
  /* Opts out of the shared `main > section` screen-height floor. This band is
	 * a closing strip — an eyebrow, a line and a button — and a full screen of
	 * pale blue under the policy would read as the page having ended early. */
  min-height: 0;
  padding-block: clamp(3rem, calc(6.5 * var(--zouma-vw)), 5.5rem);
  background: var(--zouma-blue-pale);
}

.zouma-legal-cta__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1.5rem, calc(3.5 * var(--zouma-vw)), 3rem);
}

.zouma-legal-cta__copy {
  min-width: 0;
}

.zouma-legal-cta__title {
  margin: clamp(0.75rem, calc(1.4 * var(--zouma-vw)), 1.125rem) 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-weight: 700;
}

.zouma-legal-cta__text {
  max-width: 62ch;
  margin: clamp(0.625rem, calc(1.1 * var(--zouma-vw)), 0.875rem) 0 0;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: var(--zouma-size-body);
  line-height: 1.7;
}

/* flex: 0 0 auto so the button keeps its own width and the copy takes the
 * slack, rather than the two sharing the row evenly. */
.zouma-legal-cta__btn {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 8px;
  padding: 14px 22px;
  background: var(--zouma-dark);
  border-radius: 8px;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
  transition: background var(--zouma-transition);
}

.zouma-legal-cta__btn:hover,
.zouma-legal-cta__btn:focus-visible {
  background: var(--zouma-blue);
}

/* Stacked once the row can no longer hold copy and button side by side. */
@media (max-width: 820px) {
  .zouma-legal-cta__inner {
    flex-direction: column;
    align-items: flex-start;
  }
}

.zouma-legal-cta__btn .zouma-icon--arrow-right {
  color: #fff;
  transition: transform var(--zouma-transition);
}

.zouma-legal-cta__btn:hover .zouma-icon--arrow-right {
  transform: translateX(3px);
}

/* =========================================================================
 * Partners page
 * ====================================================================== */

.zouma-pt-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Full screen on any device — the same pair the homepage hero uses.
	 *
	 * min-height rather than height, so a short screen or large type pushes
	 * the section taller instead of clipping the copy. svh after vh because
	 * 100vh on a phone measures the viewport with the browser chrome
	 * retracted, which runs taller than what the visitor can actually see;
	 * vh stays first as the fallback.
	 *
	 * The section is already pulled up under the sticky header, so the
	 * header's height is counted inside this 100. */
  /* Not a full screen on this page. The design gives the legal pages a
	 * compact masthead — an eyebrow, a title and a date — and a screenful of
	 * black above a wall of policy text reads as a loading fault rather than
	 * as space. The floor here is roughly what the design measures. */
  min-height: clamp(15rem, calc(20 * var(--zouma-vw)), 18rem);
  margin-top: calc(-1 * var(--zouma-header-h));
  padding-top: var(--zouma-header-h);
  background: #0d0d0d;
  color: #fff;
  overflow: hidden;
}

/* Two full-bleed columns, no centred container: the design runs the dark panel
 * to the left edge of the screen and the photograph to the right edge, with
 * the split at 46/54 and no gap between them. A max-width wrapper would leave
 * the artwork stopping short of the edge on a wide display. */
.zouma-pt-hero__grid {
  display: grid;
  grid-template-columns: 46% 54%;
  align-items: center;
  gap: 0;
  min-height: clamp(28rem, calc(52 * var(--zouma-vw)), 47rem);
}

.zouma-pt-hero__copy {
  /* Matches the design's 8% inset from the left edge. */
  padding-block: clamp(2.5rem, calc(5 * var(--zouma-vw)), 4.5rem);
  padding-left: clamp(1.25rem, calc(8 * var(--zouma-vw)), 7rem);
  padding-right: clamp(1.25rem, calc(3 * var(--zouma-vw)), 3rem);
}

.zouma-pt-hero__title {
  margin: 14px 0 0;
  font-family: var(--zouma-font-heading);
  font-size: clamp(2rem, 1.2rem + calc(2.4 * var(--zouma-vw)), 3rem);
  font-weight: 700;
  line-height: 1.16;
}

.zouma-pt-hero__text {
  max-width: 46ch;
  margin: 16px 0 0;
  color: rgba(255, 255, 255, 0.66);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.75;
}

.zouma-pt-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 26px;
}

.zouma-pt-hero__media {
  position: relative;
  align-self: stretch;
}

.zouma-pt-hero__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Trust strip along the foot of the hero. */
.zouma-pt-hero__bar {
  position: relative;
  background: #121a1f;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.zouma-pt-hero__bar-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1rem, calc(2.6 * var(--zouma-vw)), 2.5rem);
  max-width: 1560px;
  margin: 0 auto;
  padding: 12px clamp(1rem, calc(3 * var(--zouma-vw)), 2.5rem);
  list-style: none;
}

.zouma-pt-hero__bar-list li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--zouma-font-body);
  font-size: 0.6875rem;
  font-weight: 500;
}

/* The bullet between the items on the hero bar. Same story as the What We Do,
 * Industries and Case Studies bars: a background of icon-spark.png, a file
 * that no longer exists, failing silently and drawing nothing. 6px, round and
 * cyan, as those three now are. */
.zouma-pt-hero__dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--zouma-cyan);
}

/* About ------------------------------------------------------------------ */

/* The partners design measures 1280px of content, not the site's usual 1240.
 *
 * .zouma-shell is max-width 1320 with 40px of inline padding at this width,
 * which leaves 1240 — so every element on the page sat ~20px in from where the
 * design puts it, on both sides. Widening the box by the padding restores the
 * intended 1280 and lands the left edge on 225 and the right on 1505, exactly
 * as drawn. */
.zouma-pt-about .zouma-shell,
.zouma-pt-why .zouma-shell,
.zouma-pt-routes .zouma-shell,
.zouma-pt-journey .zouma-shell,
.zouma-pt-stories .zouma-shell,
.zouma-pt-tiers .zouma-shell,
.zouma-pt-cta .zouma-shell {
  max-width: 1360px;
}

/* Opted out of the site-wide full-screen floor (see `main > section` at the
 * foot of this file). Six of the eight bands on this page hold between 200 and
 * 1,200px of content, so a screen-height floor left roughly 2,900px of empty
 * band down the page — the single biggest reason it did not read as the
 * design. The hero keeps its own shorter floor, and .zouma-pt-stories opts out
 * in its own rule.
 *
 * Both declarations, not just min-height: the floor arrives with
 * `display: grid; align-content: center`, and releasing the height alone
 * leaves the content centred inside a box that no longer needs centring.
 *
 * Stated as classes here rather than added to the shared opt-out list further
 * down, because a class is (0,1,0) against that rule's (0,0,2) and wins
 * wherever it sits in the file.
 *
 * The padding is what supplies the rhythm the floor was standing in for — the
 * same clamp() shape .zouma-indlist and .zouma-ctoff use, a step down from
 * what these bands carried before, since none of them is being padded out to
 * a screen any more. */
.zouma-pt-about,
.zouma-pt-why,
.zouma-pt-routes,
.zouma-pt-journey,
.zouma-pt-tiers,
.zouma-pt-cta {
  min-height: auto;
  display: block;
  padding-block: clamp(2.5rem, calc(4 * var(--zouma-vw)), 3.75rem);
}

.zouma-pt-about {
  background: #fff;
}

/* 580 / 626 with a 74px gutter, measured off the 1280px design container.
 * The design is drawn at a fixed container width rather than a percentage of
 * the frame, so these proportions hold at any viewport above it. */
.zouma-pt-about__grid {
  display: grid;
  grid-template-columns: minmax(0, 580fr) minmax(0, 626fr);
  align-items: start;
  gap: clamp(2rem, calc(5.1 * var(--zouma-vw)), 4.625rem);
}

.zouma-pt-about__title {
  max-width: 20ch;
  margin: 18px 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  /* 40/50 in the design. */
  font-size: clamp(1.75rem, 1.2rem + calc(1.9 * var(--zouma-vw)), 2.5rem);
  font-weight: 700;
  line-height: 1.25;
}

.zouma-pt-about__text {
  margin-top: 20px;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  /* 16/29 in the design — the body copy here is a step larger than the
	 * card text elsewhere on the page. */
  font-size: clamp(0.875rem, 0.78rem + calc(0.35 * var(--zouma-vw)), 1rem);
  line-height: 1.8;
}

/* The design leaves a clear break between the two paragraphs, wider than a
 * normal paragraph gap. */
.zouma-pt-about__text p {
  margin: 0 0 44px;
}

.zouma-pt-about__text p:last-child {
  margin-bottom: 0;
}

/* The right-hand column: one figure, and the rest of the stats only when the
 * editor asks for them. */
.zouma-pt-about__side {
  display: grid;
  gap: 28px;
}

/* The single number the design leads on. No card behind it — the pale panel the
 * four stats sat in was there to group them, and one figure has nothing to be
 * grouped with. */
.zouma-pt-about__figure {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Off the h1 scale rather than the stat scale: this is the largest thing in the
 * section and the design sets it against the heading, not against the body. */
.zouma-pt-figure__value {
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  font-size: var(--zouma-size-hero);
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.05;
}

.zouma-pt-figure__label {
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.875rem, 0.7rem + calc(0.63 * var(--zouma-vw)), 1.25rem);
}

/* Row gap is wider than the column gap in the design — 36 against 16 — so the
 * four cards read as two pairs rather than one block. */
.zouma-pt-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 28px 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 304 x 172 in the design; the height comes from the padding rather than a
 * fixed value so a longer label cannot clip. */
.zouma-pt-stat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 24px;
  min-height: clamp(7rem, calc(11.95 * var(--zouma-vw)), 10.75rem);
  /* Narrow side padding on purpose: the longest value, "UAE · UK · India",
	 * is a single line in the design and needs almost the full card width at
	 * 36px. Wider padding tips it onto two lines and the row stops matching. */
  padding: 24px 12px;
  background: var(--zouma-blue-pale);
  border-radius: 10px;
  text-align: center;
}

.zouma-pt-stat__value {
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  /* 36px in the design. */
  font-size: clamp(1.5rem, 1.1rem + calc(1.4 * var(--zouma-vw)), 2.125rem);
  font-weight: 700;
  line-height: 1.1;
}

.zouma-pt-stat__label {
  color: #5b6770;
  font-family: var(--zouma-font-body);
  /* 18px in the design. */
  font-size: clamp(0.875rem, 0.7rem + calc(0.63 * var(--zouma-vw)), 1.25rem);
}

/* Why partner ------------------------------------------------------------ */

.zouma-pt-why {
  background: #fff;
}

.zouma-pt-why__title {
  max-width: 26ch;
  margin: 14px 0 26px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.5 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.25;
}

/* Four blocks stacked down the band, each carrying the full rail above its own
 * copy and photograph.
 *
 * No card. The white fill and the 12px radius only ever read as a card because
 * the band behind them was blue; on the white band the design has the blocks
 * sitting directly on the page, separated by the rail's own rule. The inline
 * padding goes with them, so the copy lines up on the shell edge the heading
 * and every other band align to — only the vertical rhythm is kept. */
.zouma-pt-why__block {
  display: grid;
  /* One track is the shipping state.
   *
   * The photographs are not in the repository yet, and the template only emits
   * .zouma-pt-why__media once the file resolves, so a two-column base would
   * leave every block half empty until the client's artwork lands. Two columns
   * are promoted below, from the media's own presence. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0 clamp(1.5rem, calc(3.4 * var(--zouma-vw)), 3.25rem);
  align-items: center;
  padding-block: 0 clamp(1.5rem, calc(2.6 * var(--zouma-vw)), 2.25rem);
}

.zouma-pt-why__block + .zouma-pt-why__block {
  margin-top: clamp(1rem, calc(1.8 * var(--zouma-vw)), 1.5rem);
}

/* Copy left, photograph right, on every block — the design does not alternate,
 * so there is no :nth-child here on purpose. */
.zouma-pt-why__block:has(.zouma-pt-why__media) {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* The rail runs the width of the block, above both columns. */
.zouma-pt-why__rail {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 0 clamp(1rem, calc(2 * var(--zouma-vw)), 2.25rem);
  margin: 0 0 clamp(1rem, calc(1.8 * var(--zouma-vw)), 1.5rem);
  padding: 0 0 2px;
  border-bottom: 1px solid var(--zouma-blue-pale);
  list-style: none;
}

/* Marks the block you are looking at against the other three. Not a control:
 * see the note in page-partners.php — no button, no tab role, nothing
 * focusable, so there is no hover or focus state to write. */
.zouma-pt-why__rail-item {
  position: relative;
  margin: 0;
  padding: 0 0 10px;
  color: var(--zouma-color-muted);
  font-family: var(--zouma-font-body);
  font-size: clamp(0.6875rem, 0.65rem + calc(0.2 * var(--zouma-vw)), 0.8125rem);
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 1.3;
  text-transform: uppercase;
}

.zouma-pt-why__rail-item.is-active {
  color: var(--zouma-color-text);
}

/* The marker sits on the list's own border, so the two read as one rule with a
 * lit segment rather than as two separate lines. */
.zouma-pt-why__rail-item.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 2px;
  background: var(--zouma-blue);
}

.zouma-pt-why__num {
  display: block;
  color: #9fb2c2;
  font-family: var(--zouma-font-heading);
  font-size: 0.75rem;
  font-weight: 700;
}

.zouma-pt-why__name {
  margin: 10px 0 10px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1rem, 0.9rem + calc(0.5 * var(--zouma-vw)), 1.25rem);
  font-weight: 700;
  line-height: 1.35;
}

.zouma-pt-why__text {
  max-width: 56ch;
  margin: 0;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.75;
}

.zouma-pt-why__media {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: 10px;
  background: var(--zouma-blue-pale);
}

.zouma-pt-why__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Routes ----------------------------------------------------------------- */

/* The one dark band in the upper half of the page, on the shared teal token
 * rather than a fill of its own. Everything inside it inverts below; the
 * colour here is the inherited default, so anything added to the section later
 * is legible without being told. */
.zouma-pt-routes {
  background: var(--zouma-teal-deep);
  color: #fff;
}

/* The same sky the other dark bands give their eyebrow. `.zouma-eyebrow`
 * carries the muted ink at (0,1,0), so this needs the section in front of it
 * to win. */
.zouma-pt-routes .zouma-eyebrow {
  color: var(--zouma-sky);
}

.zouma-pt-routes__title {
  margin: 14px 0 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.5 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.25;
}

.zouma-pt-routes__lede {
  max-width: 62ch;
  margin: 12px 0 0;
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
}

/* The heading holds one column and the four routes the other, rather than a
 * band of copy over a row of cards. */
.zouma-pt-routes__grid {
  display: grid;
  grid-template-columns: minmax(0, 470fr) minmax(0, 714fr);
  align-items: start;
  gap: clamp(2rem, calc(5.1 * var(--zouma-vw)), 4.625rem);
}

/* A hairline between neighbours, not a box around each: four rows reading as
 * one list. */
.zouma-pt-route + .zouma-pt-route {
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
}

.zouma-pt-route__name {
  margin: 0 0 8px;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
}

.zouma-pt-route__text {
  margin: 0;
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.75;
}

/* Journey ---------------------------------------------------------------- */

.zouma-pt-journey {
  background: #fff;
}

.zouma-pt-journey__title {
  max-width: 40ch;
  margin: 14px 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.5 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.25;
}

.zouma-pt-journey__lede {
  max-width: 68ch;
  margin: 12px 0 26px;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
}

.zouma-pt-journey__grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: clamp(1rem, calc(2 * var(--zouma-vw)), 1.75rem);
}

/* One rule across all five, drawn on the grid itself.
 *
 * Five per-column segments butted end to end would break at every gap and
 * would not line up once the columns round to fractional pixels; a single
 * element cannot do either. It is inset by half a dot so it starts and ends
 * under the first and last markers rather than running past them. */
.zouma-pt-journey__grid::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 5px;
  right: 5px;
  height: 1px;
  background: #c3d8ea;
}

.zouma-pt-phase {
  position: relative;
  /* A grid item's min-width: auto floor. The five headings are uppercase and
   * do not wrap mid-word, so their min-content width pushed the track — and
   * the grid — past the viewport, where .zouma-site's overflow-x: clip hides
   * it rather than scrolling to it. */
  min-width: 0;
  padding-top: 30px;
}

/* The marker on the rule. The ring is the band's own colour, so the rule stops
 * cleanly at the dot instead of running underneath it. */
.zouma-pt-phase::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--zouma-blue);
  box-shadow: 0 0 0 4px #fff;
}

.zouma-pt-phase__num {
  display: block;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-heading);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1;
}

.zouma-pt-phase__name {
  margin: 12px 0 8px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.35;
}

.zouma-pt-phase__text {
  margin: 0;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.6875rem;
  line-height: 1.7;
}

/* Tiers ------------------------------------------------------------------ */

.zouma-pt-tiers {
  background: var(--zouma-blue-pale);
}

.zouma-pt-tiers__title {
  margin: 14px 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.5 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.25;
}

.zouma-pt-tiers__lede {
  max-width: 68ch;
  margin: 12px 0 30px;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
}

.zouma-pt-tiers__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, calc(2 * var(--zouma-vw)), 1.5rem);
  align-items: start;
}

.zouma-pt-tier {
  position: relative;
  padding: 26px 24px 28px;
  background: #fff;
  border: 1px solid #e6edf4;
  border-radius: 12px;
}

/* Bounded, not sized: the handshake mark is supplied by the client and could
 * arrive at any dimension, so the box fixes the height the three names line up
 * on and the artwork fits inside it. */
.zouma-pt-tier__icon {
  display: flex;
  align-items: center;
  height: 40px;
  margin-bottom: 16px;
}

.zouma-pt-tier__icon img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 100%;
  object-fit: contain;
}

.zouma-pt-tier__facts {
  margin: 0;
}

.zouma-pt-tier__term {
  color: #9fb2c2;
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1.3;
  text-transform: uppercase;
}

.zouma-pt-tier__scope,
.zouma-pt-tier__role {
  /* The UA indents every dd by 40px. */
  margin: 6px 0 0;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.75;
}

.zouma-pt-tier__scope {
  margin-bottom: 18px;
}

/* The middle tier is the one being pushed, so it carries the accent border
 * and the badge that names it. */
.zouma-pt-tier.is-featured {
  border-color: var(--zouma-cyan);
  box-shadow: 0 10px 30px rgba(14, 133, 182, 0.08);
}

.zouma-pt-tier__badge {
  position: absolute;
  top: 0;
  left: 50%;
  padding: 4px 12px;
  background: var(--zouma-cyan);
  border-radius: 0 0 6px 6px;
  color: #fff;
  font-family: var(--zouma-font-body);
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transform: translateX(-50%);
  white-space: nowrap;
}

.zouma-pt-tier__name {
  margin: 0 0 8px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 1.125rem;
  font-weight: 700;
}

.zouma-pt-tier__text {
  margin: 0 0 16px;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  line-height: 1.7;
}

.zouma-pt-tier__list {
  margin: 0;
  padding-left: 28px;
  list-style: none;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.75rem;
  line-height: 1.7;
}

.zouma-pt-tier__list li {
  position: relative;
  margin-bottom: 8px;
}

/* Same reason as the legal list above, and the same fix: icon-spark.png is
 * gone, so the mark was drawing nothing at all. The offsets put the 5px dot's
 * centre exactly where the 12px artwork's centre sat, so the indent is
 * unchanged. */
.zouma-pt-tier__list li::before {
  content: "";
  position: absolute;
  left: -16.5px;
  top: calc(0.36em + 3.5px);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
}

.zouma-pt-tier__list li:last-child {
  margin-bottom: 0;
}

/* Partner stories -------------------------------------------------------- */

/* The same dark ground the homepage testimonials band uses, so the one rail
 * component appears on one colour across the site. */
.zouma-pt-stories {
  /* Opting out of the full-screen floor, both halves of it.
   *
   * `main > section` sets min-height: 100vh together with display: grid and
   * align-content: center. Releasing the height alone leaves the grid centring
   * a stack inside a box that is no longer taller than its contents, which
   * reads as a random top margin the moment the rail's height changes. */
  min-height: auto;
  display: block;
  padding-block: clamp(3.5rem, calc(7 * var(--zouma-vw)), 7.5rem);
  background: #0a0e12;
  /* Every descendant here sets its own colour, so the band looked right while
   * inheriting the page's near-black ink — anything added later would have
   * been invisible. */
  color: #fff;
}

.zouma-pt-stories__head {
  margin-bottom: clamp(2rem, calc(3.6 * var(--zouma-vw)), 3rem);
}

.zouma-pt-stories__title {
  max-width: 24ch;
  margin: 14px 0 0;
  color: #fff;
  font-family: var(--zouma-font-heading);
  font-weight: 700;
}

.zouma-pt-stories__lede {
  max-width: 68ch;
  margin: 12px 0 0;
  color: rgba(255, 255, 255, 0.66);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
}

/* Two cards at a time rather than the rail's default three — the story cards
 * carry a label, a meta line, a quote and an attribution, and three across at
 * this container width leaves the quote too narrow to read.
 *
 * --zouma-quotes-cols is the documented knob for this and is the only figure
 * that has to change: the cards divide whatever the scroller measures and the
 * arrows read a card's real width at click time. */
.zouma-pt-stories__rail {
  --zouma-quotes-cols: 2;
}

/* The rail's own 560px step down to a single card is stated again here.
 *
 * That rule targets .zouma-quotes, the same (0,1,0) as the class above, and it
 * sits earlier in this file — so without this the override above would win
 * inside the media query and a phone would be asked to fit two cards across. */
@media (max-width: 560px) {
  .zouma-pt-stories__rail {
    --zouma-quotes-cols: 1;
  }
}

/* White cards on the dark band, against .zouma-quote's teal.
 *
 * Same specificity as the rule it overrides, so this only holds because the
 * Partners block sits below the testimonials block in this file. Moving either
 * one past the other puts the cards back to teal without any selector looking
 * wrong. */
.zouma-pt-story {
  background: #fff;
}

.zouma-pt-story__label {
  margin: 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
}

.zouma-pt-story__meta {
  margin: 6px 0 16px;
  color: var(--zouma-blue);
  font-family: var(--zouma-font-body);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 1.3;
  text-transform: uppercase;
}

/* The shared card text is written for a dark ground. */
.zouma-pt-story .zouma-quote__text {
  color: #5b6770;
  font-size: 0.8125rem;
}

/* Pinned to the foot of the card so the attributions line up across the rail
 * however long the quotes run. */
.zouma-pt-story__by {
  margin-top: auto;
  padding-top: 20px;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.5;
}

/* Closing CTA ------------------------------------------------------------ */

/* A step tighter than the six bands above, the proportion it already had. */
.zouma-pt-cta {
  padding-block: clamp(2rem, calc(3.4 * var(--zouma-vw)), 3.25rem);
  background: #fff;
}

.zouma-pt-cta__inner {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.5rem, calc(3 * var(--zouma-vw)), 3rem);
}

.zouma-pt-cta__title {
  margin: 14px 0 0;
  color: var(--zouma-color-text);
  font-family: var(--zouma-font-heading);
  font-size: clamp(1.5rem, 1.1rem + calc(1.5 * var(--zouma-vw)), 2rem);
  font-weight: 700;
  line-height: 1.25;
}

.zouma-pt-cta__text {
  max-width: 60ch;
  margin: 12px 0 0;
  color: #5b6770;
  font-family: var(--zouma-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
}

.zouma-pt-cta__actions {
  display: flex;
  flex-shrink: 0;
  gap: 12px;
}

@media (max-width: 1024px) {
  .zouma-pt-hero__grid,
  .zouma-pt-about__grid,
  .zouma-pt-routes__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-pt-cta__inner {
    flex-direction: column;
    align-items: flex-start;
  }

  .zouma-pt-journey__grid,
  .zouma-pt-tiers__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* The photograph goes under the copy rather than beside it, so the promotion
   * to two columns has to be undone at the same specificity or higher. */
  .zouma-pt-why__block:has(.zouma-pt-why__media) {
    grid-template-columns: minmax(0, 1fr);
  }

  .zouma-pt-why__media {
    margin-top: 20px;
  }

  /* The rule only reads as a timeline while the five steps are one row. */
  .zouma-pt-journey__grid::before {
    display: none;
  }
}

@media (max-width: 620px) {
  .zouma-pt-stats,
  .zouma-pt-journey__grid,
  .zouma-pt-tiers__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* =========================================================================
 * Section headings — one size, everywhere.
 *
 * Per the brand direction: 48px on 105% leading. These titles were set in
 * eleven different stylesheets and ranged from 30px to 53px, so a single
 * token on the base h2 rule was not enough on its own — the page sheets load
 * after this one and their own .class rules would have won on order.
 *
 * Hence h2.class rather than .class: element-plus-class is (0,1,1) against a
 * bare class's (0,1,0), so it wins on specificity no matter what loads after,
 * without reaching for !important. It also means a class reused on an h3
 * somewhere is left alone, which a bare class selector could not promise.
 *
 * Deliberately excluded — card titles and footer column labels that are
 * marked up as h2 but are not section headings, and would be broken by 48px:
 *   zouma-bkhero__card-title, zouma-card__title, zouma-esgcard__title,
 *   zouma-pilhero__whotitle, zouma-pilmid__title, zouma-stsvc__name,
 *   zouma-cslist__title, zouma-indv__name
 * ====================================================================== */

h2.zouma-abcta__title,
h2.zouma-bkexpect__title,
h2.zouma-blog__title,
h2.zouma-careers__title,
h2.zouma-core__title,
h2.zouma-crben__title,
h2.zouma-crjobs__title,
h2.zouma-crjoin__title,
h2.zouma-crlife__title,
h2.zouma-cscta__title,
h2.zouma-ctcert__title,
h2.zouma-ctoff__title,
h2.zouma-esgdisc__title,
h2.zouma-footer__heading,
h2.zouma-global__title,
h2.zouma-indcta__title,
h2.zouma-indways__title,
h2.zouma-instinct__title,
h2.zouma-journey__title,
h2.zouma-ms__title,
h2.zouma-outcomes__title,
h2.zouma-pilend__title,
h2.zouma-pillars__title,
h2.zouma-pilpkg__title,
h2.zouma-piltow__title,
h2.zouma-pt-about__title,
h2.zouma-pt-cta__title,
h2.zouma-pt-journey__title,
h2.zouma-pt-routes__title,
h2.zouma-pt-stories__title,
h2.zouma-pt-tiers__title,
h2.zouma-pt-why__title,
h2.zouma-section-title,
h2.zouma-stats__title,
h2.zouma-stcur__title,
h2.zouma-story__title,
h2.zouma-stsla__title,
h2.zouma-sun__title,
h2.zouma-team__title,
h2.zouma-testimonials__title,
h2.zouma-values__title,
h2.zouma-whois__title,
h2.zouma-wwdcta__title,
h2.zouma-wwdins__title,
h2.zouma-wwdpil__title,
h2.zouma-wwdpro__title {
  font-size: var(--zouma-size-h2);
  line-height: var(--zouma-lh-h2);
}

/* =========================================================================
 * Every section a full screen
 * =========================================================================
 *
 * min-height rather than height. A hard height would cut the long sections
 * dead - the What We Do pillars run 2021px and the Industries list 6202px -
 * with no way to reach what was cut. min-height gives the same floor and
 * lets those keep their own length.
 *
 * svh after vh: 100vh on a phone measures the viewport with the browser
 * chrome retracted, so it runs taller than what the visitor can see.
 *
 * Type selectors only, no class, and that is deliberate: this rule has to
 * sit BELOW every existing section rule in specificity so the heroes keep
 * their own calc(100svh - header) and any section with a considered layout
 * keeps it. This only supplies a floor where nothing else has an opinion.
 *
 * The grid is what centres the content in the taller box. A single-column
 * grid stacks children exactly as block flow does, so nothing moves
 * sideways; align-content centres the stack instead of leaving it pinned to
 * the top with the new space dumped underneath. */
main > section {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-content: center;
}

/* Sections that size to their content instead of the screen.
 *
 * The floor above gives every band at least a screenful, which suits the hero
 * and the two full-bleed photo panels but leaves the rest padding themselves
 * out with empty space — worse the taller the window, because the floor grows
 * with it while the content does not. On a 1200px-tall window these five were
 * carrying between 258 and 422 pixels of nothing each.
 *
 * Stated as a class rather than deleted from the rule above, because
 * `main > section` is (0,0,2) and a class outranks it — the same way
 * .zouma-whois, .zouma-stats and .zouma-careers already opt out.
 *
 * Each of these still measures 778–942px of its own accord, so nothing
 * collapses; the band simply stops growing past what it holds.
 */
.zouma-pillars,
.zouma-sun,
.zouma-standards,
.zouma-outcomes,
.zouma-testimonials {
  min-height: auto;
}


/* =========================================================================
 * Footer links on a phone — hit area only.
 *
 * The footer's link lists sit at 14px over a 1.5 line-height, so each anchor
 * is a 21px box, and the legal row and office phone/email links are the same
 * or smaller. WCAG 2.2 asks for 24px; on a thumb these were being missed.
 *
 * The rhythm is deliberately left alone. The stacked lists carry their 8px
 * separation as `li + li` margin, which is dead space no thumb can use, so
 * it is moved into the anchor as padding instead: 21 + 8 = 29px of hit box
 * at the same 29px pitch the design already had. Only the first item's text
 * shifts, by 4px. The legal row and the office links have no such margin to
 * borrow, so those take the padding as a real 8px gain.
 *
 * Phone widths only — there is nothing to fix with a mouse.
 * ====================================================================== */

@media (max-width: 640px) {
  .zouma-footer__group a,
  .zouma-footer__legal a,
  .zouma-office__link {
    display: block;
    padding-block: 4px;
  }

  /* Given to the anchors above, so the pitch does not change. */
  .zouma-footer__group li + li {
    margin-top: 0;
  }
}


/* =========================================================================
 * Language switcher.
 *
 * The trigger already existed as a dead button with a caret; this gives it the
 * menu the caret was promising.
 *
 * Opens on hover and on keyboard focus. The gap between the trigger and the
 * panel is bridged by padding-top on the panel rather than a margin, so the
 * pointer never crosses dead space on its way down and the menu does not close
 * out from under it.
 * ====================================================================== */

.zouma-lang-switch {
  position: relative;
}

.zouma-lang-switch__menu {
  position: absolute;
  top: 100%;
  /* Hangs from the same edge the header aligns to, so it flips with the page
   * in Arabic without a second rule. */
  inset-inline-end: 0;
  z-index: 60;
  min-width: 9.5rem;
  margin: 0;
  /* The bridge: the panel starts at the trigger's bottom edge and pads itself
   * down, so there is no gap for the pointer to fall through. */
  padding: 8px 0 0;
  list-style: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition:
    opacity 160ms ease,
    transform 160ms ease,
    visibility 0s linear 160ms;
}

.zouma-lang-switch:hover .zouma-lang-switch__menu,
.zouma-lang-switch:focus-within .zouma-lang-switch__menu,
.zouma-lang-switch.is-open .zouma-lang-switch__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

/* The panel itself, so the padding above stays transparent. */
.zouma-lang-switch__menu li {
  background: #14181d;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-block-end: 0;
}

.zouma-lang-switch__menu li:first-child {
  border-start-start-radius: 8px;
  border-start-end-radius: 8px;
}

.zouma-lang-switch__menu li:last-child {
  border-block-end: 1px solid rgba(255, 255, 255, 0.1);
  border-end-start-radius: 8px;
  border-end-end-radius: 8px;
}

.zouma-lang-switch__option {
  display: block;
  padding: 10px 16px;
  color: rgba(255, 255, 255, 0.72);
  font-family: var(--zouma-font-body);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--zouma-transition), background var(--zouma-transition);
}

.zouma-lang-switch__option:hover,
.zouma-lang-switch__option:focus-visible {
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
}

.zouma-lang-switch__option.is-current {
  color: var(--zouma-cyan);
}

/* Arabic is set in the site's body face, which has no Arabic glyphs, so the
 * browser would fall back per-character and the name would come out uneven.
 * Naming the stack keeps it in one typeface. */
.zouma-lang-switch__option[lang="ar"] {
  font-family: "Noto Naskh Arabic", "Segoe UI", "Tahoma", sans-serif;
  font-size: 15px;
}

/* The heading on a phone.
 *
 * Section headings are pinned to 48px by the brand rule (--zouma-size-h2),
 * which is right on a desktop, where this one sets on a single line. It does
 * not scale down, and this is the longest heading on the site: at 390px it
 * ran to three lines and at 320px to five. Reaching 48px again at 700px, so
 * the desktop and tablet typography are untouched. */
@media (max-width: 699px) {
  h2.zouma-careers__title {
    font-size: clamp(1.25rem, 0.2rem + 5.2vw, 3rem);
    line-height: 1.15;
  }
}
