/* ================================================================
   Forma Media — quiet luxury design system
   Navy var(--navy) · Supporting var(--navy) · Warm white var(--blanc)
   Light gray var(--rule) · White #FFFFFF
   Headings: Inter grotesque (Neue Haas Grotesk fallback stack)
   Emphasis: Fraunces italic — the serif voice kept for <em> words
   Body: Inter (Neue Haas Grotesk fallback stack)
   ================================================================ */

/* ---------- Fonts (self-hosted) ---------- */
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-v38-latin-regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-v38-latin-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-v38-latin-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-v38-latin-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("../fonts/fraunces-v38-latin-500italic.woff2") format("woff2");
  font-weight: 500; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-v20-latin-300.woff2") format("woff2");
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-v20-latin-regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-v20-latin-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  /* Forma palette (docs/Newforma.md). Four brand colours and one ground —
     there is no ramp any more, and nothing on the page is a gradient. */
  --ground: #FFFFFF;          /* the page: a clean white, not an off-white */
  --navy: #13273F;            /* Mystic Navy — headings, buttons, borders */
  --chocolate: #3B302E;       /* Chocolate Torte — the alternating heading */
  --pearl: #E6D4BC;           /* Mother of Pearl — light surfaces, accents */
  --blanc: #FBFAF7;           /* Blanc de Blanc — the light ink, on dark only */
  --white: #FFFFFF;
  --rule: rgba(19, 39, 63, 0.15);        /* the one border */
  --rule-soft: rgba(19, 39, 63, 0.08);
  /* The diagram's orbit and connectors: heavier than the border hairline,
     because they are the drawing rather than an edge between two surfaces. */
  --rule-diagram: rgba(19, 39, 63, 0.38);

  /* Older names kept so every rule that already reads one resolves to the new
     palette rather than being rewritten in place. */
  --forma-navy: var(--navy);
  --forma-white: var(--blanc);
  --off-white: var(--blanc);
  --warm-white: var(--blanc);
  --navy-deep: var(--navy);
  --ink: var(--navy);

  --display: "Inter", "Neue Haas Grotesk", "Helvetica Neue", Arial, sans-serif;
  --serif: "Fraunces", "Canela", Georgia, serif;
  --sans: "Inter", "Neue Haas Grotesk", "Helvetica Neue", Arial, sans-serif;
  --ease: cubic-bezier(0.25, 0.46, 0.45, 0.94); /* ease-out */
  --t-fast: 250ms;
  --t-slow: 400ms;

  /* Motion system. Entrances only — the parallax this used to drive is gone. */
  --ease-motion: cubic-bezier(0.22, 1, 0.36, 1);
  --t-reveal: 1.05s;
  --t-reveal-lg: 1.25s;
  --t-reveal-graphic: 1.4s;
  --motion-rise: 28px;
  --motion-shift: 20px;
}


/* A whisper of noise over the whole page. Smooth dark gradients contour at
   8-bit depth, and the bands show as faint horizontal lines; this breaks them
   up. Fixed and inert, and it sits above the body's gradient but behind
   everything else. */
body::before {
  content: "";
  position: fixed; inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  opacity: 0.05;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html {
  background: var(--ground);
  scroll-behavior: smooth;
  scroll-padding-top: 5.5rem;
  -webkit-text-size-adjust: 100%;
}
body {
  font-family: var(--sans);
  /* 400 rather than 300, and a step larger: at 300 on white the copy read as
     grey suggestion rather than text. */
  font-weight: 400;
  font-size: 1.0625rem;
  line-height: 1.7;
  letter-spacing: 0.012em;
  /* Brown is the reading colour; navy is reserved for headlines. */
  color: var(--chocolate);
  overflow-x: hidden;
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }
ul { list-style: none; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--navy); color: var(--warm-white); }

/* ---------- Utilities ---------- */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.is-hidden { display: none !important; }

.skip-link {
  position: absolute; top: -100%; left: 1rem; z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--warm-white); color: var(--navy);
  font-size: 0.8125rem; letter-spacing: 0.08em;
}
.skip-link:focus { top: 1rem; }

:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

/* ================================================================
   Loading experience — cinematic, no spinner
   ================================================================ */
#loader {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  background: var(--ground);
  animation: loader-dissolve 900ms var(--ease) 1.8s forwards;
}
#loader img {
  width: clamp(180px, 26vw, 280px);
  height: auto;
  opacity: 0;
  filter: drop-shadow(0 0 0 rgba(19, 39, 63, 0));
  animation: loader-logo 1.35s var(--ease-motion) 150ms forwards;
}
@keyframes loader-logo {
  /* Quietly materialising: up from 0.88 and 18px, no overshoot, no bounce. */
  0%   { opacity: 0; transform: translateY(18px) scale(0.88); }
  70%  { opacity: 1; }
  /* Glow follows the mark's own royal blue now, not the old cream. */
  100% { opacity: 1; transform: translateY(0) scale(1);
         filter: drop-shadow(0 18px 34px rgba(19, 39, 63, 0.14)); }
}
@keyframes loader-dissolve {
  to { opacity: 0; visibility: hidden; }
}

/* ================================================================
   Navigation
   ================================================================ */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  transition: background-color var(--t-slow) var(--ease),
              box-shadow var(--t-slow) var(--ease);
}
/* Over the navy hero the bar is transparent, so its links take the light ink;
   once it lifts off and takes its tint they go back to navy. */
.site-header:not(.scrolled) .nav-menu > li > a,
.site-header:not(.scrolled) .nav-services-toggle { color: var(--blanc); }
/* The dropdown is its own light panel, so its links keep the dark ink whatever
   the bar above them is doing. */
.nav-submenu a { color: var(--navy); }
.site-header:not(.scrolled) .nav-lang { border-color: rgba(251, 250, 247, 0.45); }
.site-header:not(.scrolled) .nav-toggle span { background: var(--blanc); }

.site-header.scrolled,
.site-header.solid {
  /* Royal-leaning, and lighter on the tint than before so the backdrop blur
     carries more of the page's own colour through — a fixed bar cannot match
     a scrolling gradient exactly, but it can stay in the same family. */
  background: rgba(247, 247, 245, 0.88);
  border-bottom: 1px solid var(--rule-soft);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.nav {
  display: flex; align-items: center; justify-content: space-between;
  max-width: 72rem; margin: 0 auto;
  padding: 1.25rem 1.5rem;
}
.nav-brand img { height: 26px; width: auto; }
.nav-brand { position: relative; display: inline-flex; transition: opacity var(--t-fast) var(--ease); }
/* The light mark over the navy hero, the ink one once the bar takes its tint.
   Both are in the DOM and cross-fade, so neither pops in on scroll. */
.nav-mark { transition: opacity var(--t-slow) var(--ease); }
.nav-mark--ink { position: absolute; left: 0; top: 0; opacity: 0; }
.site-header.scrolled .nav-mark--light { opacity: 0; }
.site-header.scrolled .nav-mark--ink { opacity: 1; }
/* Enters once, on load — never again on scroll. */
.js .nav-brand { animation: nav-brand-in 900ms var(--ease-motion) both; }
@keyframes nav-brand-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
.nav-brand:hover { opacity: 0.75; }

.nav-menu { display: flex; gap: 2.75rem; }
.nav-menu a {
  position: relative;
  color: var(--navy);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding-bottom: 0.3rem;
  transition: opacity var(--t-fast) var(--ease);
}
.nav-menu a::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.nav-menu a:hover { opacity: 0.8; }
.nav-menu a:hover::after { opacity: 0.9; }

/* ================================================================
   Our approach — the former Who we are and Why Forma Media, merged
   ================================================================ */
.approach-section {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: 190px 1.5rem 200px;
  color: var(--navy);
  /* Opens on exactly the colour the hero closes with, then climbs toward the
     mid blue that Services opens on. No reset, no boundary. */
}
/* Everything except the background sits above it. */
.approach-section > * { position: relative; z-index: 2; }

/* ---------- Our approach: layout ---------- */
.approach-intro { margin-bottom: clamp(56px, 6vw, 88px); }
.approach-copy { position: relative; z-index: 2; }
.approach-section .eyebrow { margin-bottom: 34px; }
.approach-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.4rem, 5vw, 4.1rem);
  line-height: 1.02;
  letter-spacing: -0.032em;
  margin-bottom: 30px;
}
.approach-statement {
  max-width: 44ch;
  font-size: clamp(1rem, 1.4vw, 1.15rem);
  line-height: 1.65;
  opacity: 0.82;
}

@keyframes approach-float {
  from { transform: translateY(-9px) scale(0.995); }
  to   { transform: translateY(11px) scale(1.005); }
}
.approach-tiles { margin-top: 0; }

/* ---------- Services dropdown ---------- */
.nav-has-menu { position: relative; }
.nav-services-toggle {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0 0 0.3rem;
  font: inherit;
  color: var(--navy);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  background: none; border: 0; cursor: pointer;
  transition: opacity var(--t-fast) var(--ease);
}
.nav-services-toggle:hover { opacity: 0.8; }
.nav-services-toggle svg {
  transition: transform var(--t-fast) var(--ease);
}
.nav-has-menu.open .nav-services-toggle svg { transform: rotate(180deg); }

.nav-submenu {
  position: absolute;
  top: calc(100% + 0.85rem); left: 50%;
  transform: translateX(-50%) translateY(-6px);
  min-width: 15rem;
  display: grid; gap: 0.2rem;
  padding: 0.75rem;
  border-radius: 14px;
  border: 1px solid var(--rule);
  background: rgba(251, 250, 247, 0.97);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 18px 40px rgba(19, 39, 63, 0.10);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease),
              visibility var(--t-fast) var(--ease);
  z-index: 60;
}
.nav-has-menu.open .nav-submenu {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.nav-submenu a {
  display: block;
  padding: 0.6rem 0.75rem;
  border-radius: 9px;
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.82;
  transition: background-color var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.nav-submenu a:hover { background: rgba(19, 39, 63, 0.07); opacity: 1; }

.nav-toggle {
  display: none;
  background: none; border: 0; cursor: pointer;
  width: 44px; height: 44px;
  position: relative; z-index: 60;
}
.nav-toggle span {
  display: block; width: 22px; height: 1.5px;
  background: var(--warm-white);
  margin: 5px auto;
  transition: transform var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.nav-toggle[aria-expanded="true"] span:first-child { transform: translateY(3.25px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:last-child { transform: translateY(-3.25px) rotate(-45deg); }

/* ================================================================
   Hero — endless navy canvas, floating logo
   ================================================================ */
.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  isolation: isolate;
  overflow: hidden;
  /* Darkest point of the page, but not a separate colour system: it carries
     enough mid blue to be recognisably the same environment as what follows,
     and closes on the exact colour Our Approach opens with. */
}
/* Softens the hero's lower edge into the section below. */
/* Billowing light masses (heroinspo4): several overlapping soft forms so the
   hero reads as luminous fog rather than a flat dark field. Kept translucent
   so what sits behind them still shows through. */
/* ================================================================
   Sections — editorial rhythm
   ================================================================ */
.section { padding: clamp(6rem, 12vw, 10rem) 1.5rem; }
.section-light { color: var(--navy); }
.section-warm { background: var(--warm-white); color: var(--navy); }
.section-navy { background: var(--navy); color: var(--warm-white); }

.container { max-width: 68rem; margin: 0 auto; }
.container-narrow { max-width: 46rem; }

.section-label {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 2.25rem;
}
.section-title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.85rem, 4vw, 3rem);
  line-height: 1.18;
  letter-spacing: -0.015em;
  max-width: 24ch;
  margin-bottom: 2.5rem;
}
.section-sub {
  font-size: 1rem;
  opacity: 0.8;
  margin-top: -1.25rem;
  margin-bottom: 3.5rem;
}
.section-body {
  max-width: 42rem;
  display: grid; gap: 1.5rem;
  font-size: 1rem;
}

/* Headline block — the center of the hero, heroinspo style */
.hero-lead {
  position: relative;
  text-align: center;
  display: flex; flex-direction: column; align-items: center;
  padding: 0 1.5rem;
}
.hero-headline {
  font-family: var(--display);
  /* Grotesque display wants more weight and tighter tracking than the serif
     it replaced, or it reads thin at hero scale (Fontidea.jpg). */
  font-weight: 400;
  /* The old cap of 3.6rem was reached at 1280px and never moved again, so on a
     wide or zoomed-out viewport the headline stayed put while everything around
     it reflowed — and since zooming out shrinks each CSS pixel, it read as
     getting smaller. Ceiling raised well clear of normal widths. */
  font-size: clamp(2.3rem, 5.2vw, 5.5rem);
  letter-spacing: -0.022em;
  line-height: 1.1;
  /* ch, not px: the line breaks in the same place at every size. */
  max-width: 20ch;
  color: var(--navy);
  opacity: 0;
  animation: fade-up 1.15s var(--ease-motion) 2.1s forwards;
}
.hero-headline em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.06em;
  letter-spacing: 0;
}
.hero-cta,
.btn-submit {
  /* Content-sized, not fixed. The old 200x50 stayed literal at every zoom
     level, so zooming out made the buttons grow against the headline. */
  display: inline-flex;
  align-items: center; justify-content: center;
  width: fit-content;
  min-width: 0;
  min-height: 48px;
  padding: 14px clamp(20px, 2vw, 30px);
  font-size: clamp(11px, 0.85vw, 15px);
  line-height: 1;
  white-space: nowrap;
  border-radius: 999px;
  box-sizing: border-box;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.hero-cta {
  margin-top: 26px;
  /* Primary: navy, going chocolate on hover. */
  background: var(--navy);
  color: var(--blanc);
  border: 1px solid var(--navy);
  opacity: 0;
  animation: fade-up 1.05s var(--ease-motion) 2.45s forwards;
  transition: transform 450ms var(--ease-motion), box-shadow 450ms var(--ease-motion);
}
/* A 2px lift and a little more shadow, over 450ms. The old 4px in 250ms read
   as a jump next to the rest of the motion. */
.hero-cta:hover,
.hero-cta:focus-visible {
  background: var(--chocolate);
  border-color: var(--chocolate);
  transform: translateY(-2px);
  box-shadow: 0 14px 30px rgba(19, 39, 63, 0.16);
}
/* The press is the one place a short duration is right — it has to answer the
   finger immediately. */
.hero-cta:active,
.btn-submit:active {
  transform: translateY(0) scale(0.98);
  transition-duration: 120ms;
}
.hero-sub {
  max-width: 48ch;
  margin-top: clamp(18px, 1.4vw, 28px);
  font-size: clamp(0.97rem, 1.15vw, 1.35rem);
  font-weight: 300;
  line-height: 1.75;
  color: var(--navy);
  opacity: 0;
  /* Settles at 0.8, not 1 — supporting copy sits under the headline, not beside it. */
  animation: fade-up-soft 1.05s var(--ease-motion) 2.3s forwards;
}
@keyframes fade-up-soft {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 0.8; transform: translateY(0); }
}
.hero-ctas { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px; width: 100%; }
/* Secondary: outlined until you reach for it. */
.hero-cta-ghost {
  background: transparent;
  color: var(--navy);
  border: 1px solid var(--navy);
}
.hero-cta-ghost:hover,
.hero-cta-ghost:focus-visible {
  background: var(--navy);
  color: var(--blanc);
  border-color: var(--navy);
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Scroll indicator */
/* Bottom left, hung from a vertical rail rather than centred under the copy. */

/* Eyebrow above the headline. */
.hero-eyebrow {
  font-size: clamp(0.6875rem, 0.66vw, 0.84rem);
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0;
  margin-bottom: clamp(18px, 1.6vw, 32px);
  animation: fade-up-soft 1.05s var(--ease-motion) 2.05s forwards;
}

/* ---------- Scroll reveals — applied only when JS is present ----------
   Entrances are animations, not transitions, so an element's own transition
   stays free for its hover. .service-item is the case that forced it: it lifts
   on hover over 300ms, and a transition-based reveal either took that duration
   for its entrance or left hover taking a second to respond. The animation is
   torn off again on animationend (see .motion-done) because a filled animation
   keeps overriding transform, which would pin the hover lift.

   Two families: the ones that animate `transform`, and the ones that animate
   `scale` instead, for elements whose transform is their position — the
   diagram's core, orbit and cards are held on their axes by translate(-50%),
   and `scale` composes with that rather than replacing it. */
.js .reveal,
.js .reveal-lg,
.js .reveal-left,
.js .reveal-right,
.js .reveal-pop,
.js .reveal-rise,
.js .reveal-fade,
.js .reveal-scale { opacity: 0; }

.js .reveal.in-view,
.js .reveal-lg.in-view,
.js .reveal-left.in-view,
.js .reveal-right.in-view,
.js .reveal-pop.in-view,
.js .reveal-rise.in-view,
.js .reveal-fade.in-view,
.js .reveal-scale.in-view {
  animation-duration: var(--t-reveal);
  animation-timing-function: var(--ease-motion);
  animation-delay: var(--stagger, 0ms);
  animation-fill-mode: both;
}

.js .reveal.in-view       { animation-name: reveal-rise; }
.js .reveal-lg.in-view    { animation-name: reveal-rise-lg; animation-duration: var(--t-reveal-lg); }
.js .reveal-left.in-view  { animation-name: reveal-from-left; animation-duration: var(--t-reveal-lg); }
.js .reveal-right.in-view { animation-name: reveal-from-right; animation-duration: var(--t-reveal-lg); }
.js .reveal-pop.in-view   { animation-name: reveal-pop; animation-duration: var(--t-reveal-graphic); }
.js .reveal-rise.in-view  { animation-name: reveal-arrive; animation-duration: var(--t-reveal-lg); }
.js .reveal-fade.in-view  { animation-name: reveal-soft; }
.js .reveal-scale.in-view { animation-name: reveal-emerge; }

/* Settled: hand the element back to its own styles. No will-change anywhere in
   this system — opacity and transform are composited for the duration of an
   animation regardless, and the hint left text on its own layer afterwards,
   which changed how it was antialiased. */
.js .motion-done {
  animation: none !important;
  opacity: 1;
}

@keyframes reveal-rise {
  from { opacity: 0; transform: translateY(var(--motion-rise)); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-rise-lg {
  from { opacity: 0; transform: translateY(calc(var(--motion-rise) * 0.86)) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-from-left {
  from { opacity: 0; transform: translateX(calc(var(--motion-shift) * -1)); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-from-right {
  from { opacity: 0; transform: translateX(var(--motion-shift)); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-pop {
  from { opacity: 0; transform: translateY(calc(var(--motion-rise) * 0.64)) scale(0.88); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-arrive {
  from { opacity: 0; transform: translateY(calc(var(--motion-rise) * 0.64)) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes reveal-soft {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes reveal-emerge {
  from { opacity: 0; scale: var(--reveal-from, 0.94); }
  to   { opacity: 1; scale: 1; }
}

/* The ecosystem assembles: core, then orbit, then connectors, then the four
   nodes. Order is set by the staggers in the markup; these set how long each
   part takes to settle and how far it comes from. */
.js .hub-core.in-view   { --reveal-from: 0.90; animation-duration: 1.3s; }
.js .hub-ring.in-view   { --reveal-from: 0.94; animation-duration: 1.45s; }
.js .hub-spokes.in-view { animation-duration: 1.15s; }
.js .hub-card.in-view   { --reveal-from: 0.94; animation-duration: 1s; }

/* Mixed roman/italic headline voice (heroinspo direction) */
/* The emphasis voice stays serif italic even though headlines are now a
   grotesque — that contrast is the point (heroinspo3), and the brief asks
   for the italic words to survive the font change. Serif italic runs
   optically smaller than the grotesque, so it is nudged up to match. */
h1 em, h2 em, h3 em, .section-title em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.06em;
  letter-spacing: 0;
}

/* ================================================================
   Deep-navy continuous sections (About + Services, v1.1 revision)
   ================================================================ */
.section-deep {
  position: relative;
  background: transparent;   /* the page gradient shows through */
  color: var(--navy);
  overflow: hidden;
}
/* Layer 2: grain, Layer 3: soft ambient glow */
.section-deep > * { position: relative; z-index: 1; }

.section-center { text-align: center; margin-left: auto; margin-right: auto; }
.container-narrow { max-width: 47.5rem; margin: 0 auto; padding: 0 1.5rem; }
.container-wide { width: min(92%, 1500px); margin-inline: auto; }

.eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0.8;
  margin-bottom: 32px;
}

/* ---------- About — left-aligned editorial ---------- */

/* Copy sits above the section's artwork, held to the left half so it never
   runs across the ribbon. */
.body-copy {
  font-size: 17px;
  font-weight: 400;
  line-height: 1.75;
  max-width: 640px;
  margin: 0 0 28px;
  opacity: 0.85;
}

/* ---------- Services — compact: all five boxes fit one desktop screen ---------- */
/* ================================================================
   Services — the palette's descent from navy to light blue
   ================================================================ */
.services-section {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  padding: 150px 1.5rem 170px;
  color: var(--forma-navy);
  /* Opens on var(--navy) — the colour Our Approach closes with — and the light
     occupies the lower half rather than the last few percent, so the descent
     reads as atmosphere rather than a band at the end. */
}
/* Depth over the base, kept faint: dimension, not visible discs. */
.services-section > * { position: relative; z-index: 2; }


/* Type starts light on the navy and turns dark as the ground turns pale. The
   heading block sits in the dark third; the cards sit in the light two-thirds. */
/* The section is mid blue at the top and pale at the bottom, so the heading
   block takes the dark type rather than the light — off-white on var(--navy) is
   only 3.1:1, under the 4.5 minimum. */
.services-headline,
.services-sub { color: var(--forma-navy); }
.services-sub { opacity: 0.78; }
.services-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 4.8vw, 3.8rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-bottom: 48px;
}
/* Language switch — reads as a nav item, set apart by its border */
.nav-lang {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.5rem; padding: 0.3rem 0.6rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.75;
  transition: opacity var(--t-fast) var(--ease);
}
.nav-lang:hover { opacity: 1; }

.services-sub {
  max-width: 620px;
  font-size: 16px;
  line-height: 1.8;
  opacity: 0.75;
  margin: -28px 0 44px;  /* pulls up under the headline's 48px gap */
}
.services-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px 40px;
}
.service-item {
  position: relative;
  padding: 30px 30px 32px;
  border: 1px solid rgba(19, 39, 63, 0.14);
  border-radius: 22px;
  /* The cards sit on the pale half of the gradient, so they invert: light
     glass with navy type rather than the dark glass used higher up the page. */
  background: var(--navy);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.75),
              0 16px 38px rgba(19, 39, 63, 0.10);
  color: var(--navy);
  transition: transform 300ms var(--ease), border-color 300ms var(--ease),
              box-shadow 300ms var(--ease);
}
.service-item:hover {
  transform: translateY(-4px);
  border-color: rgba(19, 39, 63, 0.22);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85),
              0 24px 50px rgba(19, 39, 63, 0.16);
}
.service-number {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-size: 1.3rem;
  opacity: 0.72;
  margin-bottom: 26px;
}
.service-lead-line {
  font-size: 1.02rem;
  font-weight: 500;
  line-height: 1.45;
  margin-bottom: 12px;
  opacity: 0.95;
}
.service-item:hover {
  transform: translateY(-4px);
}
.service-item h3 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.35rem, 1.9vw, 1.65rem);
  letter-spacing: -0.01em;
  margin-bottom: 10px;
  transition: transform 300ms var(--ease);
}
.service-item:hover h3 { transform: translateY(-2px); }
.service-item p {
  font-size: 15px;
  font-weight: 400;
  line-height: 1.65;
  max-width: 520px;
  opacity: 0.8;
  transition: opacity 300ms var(--ease);
}
.service-item:hover p { opacity: 1; }

/* ================================================================
   Why Forma Media — four supporting points, carrying the same lift
   on hover as the service boxes
   ================================================================ */
.why-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  margin-top: 56px;
}
.why-item {
  padding: 24px 24px 26px;
  /* Surface treatment lives in the shared glass-tile block below. */
  transition: transform 300ms var(--ease), border-color 300ms var(--ease),
              box-shadow 300ms var(--ease);
}
.why-item:hover {
  transform: translateY(-4px);
  border-color: rgba(19, 39, 63, 0.28);
  box-shadow: 0 22px 48px rgba(19, 39, 63, 0.158), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.why-item:hover p { opacity: 1; }
.why-number {
  display: block;
  font-family: var(--display);
  font-size: 0.95rem;
  letter-spacing: 0.15em;
  opacity: 0.72;
  margin-bottom: 14px;
}
.why-item h3 {
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}
.why-item p {
  font-size: 15px;
  line-height: 1.7;
  opacity: 0.72;
  transition: opacity 300ms var(--ease);
}

/* ================================================================
   Who We Work With — the service boxes' lift, applied to short labels
   ================================================================ */
.clients-section {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 130px 1.5rem;
  /* Carries on from Featured Work instead of returning to navy. */
  color: var(--forma-navy);
}
/* Mid-to-soft blue ground, so the tiles invert with it. */
.clients-section .eyebrow,
.clients-section .services-headline,
.clients-section .body-copy { color: var(--forma-navy); }
.clients-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 48px;
}
.client-item {
  display: flex; align-items: center;
  min-height: 96px;
  padding: 22px 24px;
  border: 1px solid rgba(19, 39, 63, 0.14);
  border-radius: 20px;
  background: var(--navy);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7),
              0 14px 32px rgba(19, 39, 63, 0.09);
  color: var(--forma-navy);
}
.client-item:hover {
  transform: translateY(-4px);
  border-color: rgba(19, 39, 63, 0.28);
  box-shadow: 0 22px 48px rgba(19, 39, 63, 0.158), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* ================================================================
   Selected Projects — editorial portfolio cards
   ================================================================ */
.section-projects {
  position: relative;
  isolation: isolate;
  padding: 170px 1.5rem 190px;
  color: var(--navy);
  overflow: hidden;
}
/* The light field spilling down out of Services. */
/* Its heading sits in the pale opening, so it takes dark type; the cards sit
   lower where the ground is deep again and keep the light treatment. */
.section-projects .eyebrow,
.projects-headline,
.projects-sub { color: var(--forma-navy); }
.projects-sub { opacity: 0.78; }
.section-projects > * { position: relative; z-index: 1; }
.projects-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.2rem, 4.2vw, 3.3rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-bottom: 24px;
}
.projects-sub {
  max-width: 600px;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.8;
  opacity: 0.8;
  margin-bottom: 64px;
}
.projects-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 50px;
}
.project-card {
  display: block;
  padding: 18px 18px 22px;
  /* Surface treatment lives in the shared glass-tile block below. */
  transition: transform 350ms var(--ease), box-shadow 350ms var(--ease),
              border-color 350ms var(--ease);
}
.project-card:hover {
  transform: translateY(-6px);
}
.project-media {
  position: relative;
  border-radius: 12px;
  aspect-ratio: 4 / 3;
  background: rgba(19, 39, 63, 0.06);
  color: var(--navy);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  margin-bottom: 22px;
  transition: transform 350ms var(--ease);
}
.project-card:hover .project-media { transform: scale(1.05); }
.project-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.project-img-contain {
  object-fit: contain;
  background: var(--white);
  padding: 10%;
}
.project-preview {
  position: relative; z-index: 1;
  font-size: 0.75rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--navy);
  background: rgba(251, 250, 247, 0.80);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  padding: 8px 16px;
  border-radius: 999px;
}
.project-media-future .project-preview {
  color: var(--navy-deep);
  background: rgba(19, 39, 63, 0.05);
}
.project-number {
  position: absolute;
  bottom: 14px; right: 18px;
  font-family: var(--display);
  font-size: 0.95rem;
  letter-spacing: 0.15em;
  opacity: 0.72;
}
.project-overlay {
  position: absolute; inset: 0;
  background: var(--navy);
  opacity: 0;
  transition: opacity 350ms var(--ease);
}
.project-card:hover .project-overlay { opacity: 0.12; }
.project-card h3 {
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.4rem;
  letter-spacing: -0.01em;
  margin-bottom: 8px;
  transition: opacity 350ms var(--ease);
}
.project-card:hover h3 { opacity: 0.75; }
.project-subtitle {
  font-size: 14.5px;
  font-weight: 400;
  line-height: 1.6;
  opacity: 0.8;
  margin-bottom: 10px;
}
.project-services {
  font-size: 11.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 16px;
}
.project-cta {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: transform 350ms var(--ease);
}
.project-card:hover .project-cta { transform: translateY(-4px); }
.project-media-future {
  background: transparent;
  border: 1px solid rgba(19, 39, 63, 0.18);
  color: var(--navy-deep);
}
.project-card-future h3 { max-width: 20ch; }

/* ================================================================
   Case study pages (/work/*) — editorial, off-white
   ================================================================ */
.case-study {
  /* The page ground carries through; case studies no longer paint their own. */
  background: none;
  color: var(--navy);
}
.case-hero {
  padding: 200px 1.5rem 60px;
}
.case-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.5rem, 5vw, 4rem);
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin-bottom: 36px;
}
.case-tags {
  display: flex; flex-wrap: wrap; gap: 10px;
}
.case-tags li {
  border: 1px solid rgba(19, 39, 63, 0.35);
  border-radius: 999px;
  padding: 8px 18px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background-color 250ms ease, color 250ms ease;
}
.case-tags li:hover {
  background: var(--off-white);
  color: var(--navy-deep);
}
.case-section { padding: 70px 1.5rem; }
.case-heading {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.6rem, 2.8vw, 2.1rem);
  letter-spacing: -0.01em;
  margin-bottom: 24px;
}
.case-body {
  font-size: 16px;
  font-weight: 400;
  line-height: 1.8;
  max-width: 47.5rem;
  opacity: 0.85;
  margin-bottom: 24px;
}
/* Case-study media strip — one straight line of images/videos */
.case-gallery { padding-top: 40px; padding-bottom: 40px; }
.case-media-row {
  display: flex;
  gap: 14px;
}
.case-media-item {
  flex: 1;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  border-radius: 14px;
  background: rgba(19, 39, 63, 0.06);
}
.case-media-item img,
.case-media-item video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
@media (max-width: 900px) {
  .case-media-row {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 8px;
  }
  .case-media-item {
    flex: 0 0 62%;
    scroll-snap-align: center;
  }
}

.case-cta {
  padding: 110px 1.5rem 150px;
  text-align: center;
}
.case-cta-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.1rem, 3.9vw, 3rem);
  letter-spacing: -0.02em;
  margin-bottom: 28px;
}
.case-cta-sub { margin-left: auto; margin-right: auto; max-width: 600px; }
.case-cta-button {
  animation: none; opacity: 1; /* .reveal drives its entrance here */
  margin-top: 8px;
}
.case-next {
  display: inline-block;
  margin-top: 36px;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.8;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.case-next:hover { opacity: 1; transform: translateX(3px); }

/* ================================================================
   Contact — compact horizontal tile on the light canvas
   ================================================================ */
.section-contact {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 160px 1.5rem 190px;
  /* Opens where Who we work with closed and brings the ice blue in. */
  color: var(--navy);
}
.section-contact > * { position: relative; z-index: 1; }
.contact-tile {
  display: grid;
  grid-template-columns: 0.85fr 1.3fr;
  gap: 20px 56px;
  align-items: start;
  padding: 44px 48px 48px;
  /* Surface treatment lives in the shared glass-tile block below. */
}
.contact-tile .section-title {
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  margin-bottom: 1.25rem;
  max-width: none;
}
.contact-tile .section-sub { margin: 0; }
.contact-tile .confirmation { grid-column: 1 / -1; }

/* ================================================================
   Contact form
   ================================================================ */
.contact-form { margin-top: 0.25rem; }
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.1rem 1.25rem;
}
.field { display: flex; flex-direction: column; }
.field-wide { grid-column: 1 / -1; }

.field label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  margin-bottom: 0.7rem;
  opacity: 0.75;
}
.field label em { text-transform: none; letter-spacing: 0.05em; font-style: normal; opacity: 0.7; }

.field input,
.field select,
.field textarea {
  font: inherit;
  font-weight: 300;
  color: var(--navy);
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 0.7rem 0.9rem;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
  width: 100%;
}
.field textarea { resize: vertical; min-height: 6.5rem; }
.field input::placeholder,
.field textarea::placeholder {
  color: rgba(19, 39, 63, 0.45);
  transition: opacity var(--t-fast) var(--ease);
}
.field input:focus::placeholder,
.field textarea:focus::placeholder { opacity: 0.4; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--navy);
  box-shadow: 0 0 0 3px var(--rule);
}
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23F8F6F2' stroke-width='1.25' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  cursor: pointer;
}

.field-error { color: #9A2B22; font-size: 0.8125rem; margin-top: 0.45rem; min-height: 1em; }
.form-errors { color: #9A2B22; font-size: 0.9rem; margin-bottom: 1.75rem; }
.form-errors ul { display: grid; gap: 0.4rem; }

.cf-turnstile { margin-top: 2rem; }

/* Submit — fully rounded pill, centered under the form */
.form-actions { text-align: center; }
.btn-submit {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  margin-top: 1.5rem;
  padding: 1.05rem 2.9rem;
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--blanc);
  background: var(--navy);
  border: 0; border-radius: 999px;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.btn-submit:hover:not(:disabled) {
  background: var(--chocolate);
  transform: translateY(-2px);
  box-shadow: 0 14px 30px rgba(19, 39, 63, 0.16);
}
.btn-submit:disabled { cursor: default; }

.btn-dots { display: none; gap: 0.35rem; }
.btn-dots i {
  width: 4px; height: 4px; border-radius: 50%;
  /* The submit pill is light now, so the busy dots have to be dark. */
  background: var(--navy-deep);
  animation: dot-pulse 1s ease-in-out infinite;
}
.btn-dots i:nth-child(2) { animation-delay: 160ms; }
.btn-dots i:nth-child(3) { animation-delay: 320ms; }
@keyframes dot-pulse {
  0%, 100% { opacity: 0.25; }
  50% { opacity: 1; }
}
.btn-submit.is-loading .btn-label { visibility: hidden; }
.btn-submit.is-loading .btn-dots {
  display: flex;
  position: absolute; inset: 0;
  align-items: center; justify-content: center;
}

/* ================================================================
   Confirmation panel
   ================================================================ */
.confirmation {
  text-align: center;
  padding: 3rem 0 1rem;
  opacity: 0;
  transform: translateY(22px);
}
.confirmation.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 500ms var(--ease), transform 500ms var(--ease);
}
.confirmation-check {
  width: 58px; height: 58px;
  margin: 0 auto 2rem;
  color: var(--navy);
  opacity: 0.95;
}
.confirmation.is-visible .check-path {
  stroke-dasharray: 40;
  stroke-dashoffset: 40;
  animation: check-draw 600ms var(--ease) 350ms forwards;
}
@keyframes check-draw { to { stroke-dashoffset: 0; } }
.confirmation h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  margin-bottom: 1.25rem;
}
.confirmation p {
  max-width: 34rem;
  margin: 0 auto 0.9rem;
  opacity: 0.8;
  font-size: 1rem;
}

/* ================================================================
   Footer — centered, engraved mark
   ================================================================ */
.site-footer {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  text-align: center;
  padding: 5.5rem 1.5rem 4.5rem;
  color: var(--navy);
  border-top: 1px solid var(--rule-soft);
}
.site-footer > * { position: relative; z-index: 5; }
.footer-mark {
  /* Silver on navy reads brighter than the royal-gradient mark it replaced,
     so it is held back a little further here. */
  width: 64px;
  margin: 0 auto 1.75rem;
  opacity: 0.72;
}
.footer-location {
  font-size: 0.8125rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 0.6rem;
}
.footer-copy {
  font-size: 0.8125rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.75;
  margin-bottom: 1.5rem;
}
.footer-links {
  display: flex; justify-content: center; align-items: center; gap: 2.5rem;
  font-size: 0.875rem; letter-spacing: 0.06em;
}
.footer-social-group { display: flex; gap: 0.5rem; }
/* 44px tap target around a 21px glyph; negative margin keeps it from padding the row out. */
.footer-social {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; margin: -0.75rem 0;
}
.footer-links a { opacity: 0.75; transition: opacity var(--t-fast) var(--ease); }
.footer-links a:hover { opacity: 1; }
.footer-version {
  margin-top: 2rem;
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  opacity: 0.55; /* 0.3 fails WCAG contrast on navy */
}

/* ================================================================
   Glass tile — one treatment for every tile on the site (square.jpg)

   Dark translucent glass, a hairline light edge, a faint inner grid, and a
   blue glow rising from the bottom. Declared after the individual tile rules
   so it supersedes their older looks (the white cards especially), but before
   the responsive blocks so their layout overrides still win.
   ::after carries the glow at z-index -1 inside the tile's own stacking
   context, so tile content stays untouched.
   ================================================================ */
.why-item,
.contact-tile,
.project-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border-radius: 24px;
  border: 1px solid var(--rule);
  background: var(--navy);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85),
              0 12px 30px rgba(19, 39, 63, 0.07);
  color: var(--navy);
}
/* The glass reflect: a highlight raking across the top of every tile. Sits
   above the tile's own background and below its content, and never takes a
   pointer event. */
.service-item::after,
.why-item::after,
.client-item::after,
.project-card::after,
.hub-card::after,
.contact-tile::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(158deg,
      rgba(255, 255, 255, 0.17) 0%,
      rgba(255, 255, 255, 0.05) 32%,
      transparent 58%);
  pointer-events: none;
}
.service-item > *,
.why-item > *,
.client-item > *,
.project-card > *,
.hub-card > *,
.contact-tile > * { position: relative; z-index: 1; }

/* And one interaction, the Featured Work card's: a six-pixel lift, the border
   coming up, and a shadow that stays small. */
.service-item,
.why-item,
.client-item,
.project-card,
.hub-card,
.contact-tile {
  position: relative;
  transition: transform 420ms var(--ease-motion),
              border-color 420ms var(--ease-motion),
              box-shadow 420ms var(--ease-motion);
  box-shadow: 0 6px 16px rgba(19, 39, 63, 0.10);
}
.service-item:hover,
.why-item:hover,
.client-item:hover,
.project-card:hover,
.hub-card:hover,
.contact-tile:hover {
  border-color: rgba(251, 250, 247, 0.32);
  box-shadow: 0 12px 26px rgba(19, 39, 63, 0.16);
}
.service-item:hover,
.why-item:hover,
.client-item:hover,
.project-card:hover,
.contact-tile:hover { transform: translateY(-6px); }

/* The diagram's cards are held on their axes by a transform of their own
   (translateX(-50%) and the like), so lifting them with transform replaced
   that and threw each card half its own width off centre. It landed away from
   the pointer, un-hovered, snapped back and hovered again — the flicker.
   `translate` is a separate property and composes with the transform instead
   of overwriting it, the same split the reveals and the parallax already use. */
.hub-card { transition-property: translate, border-color, box-shadow; }
.hub-card:hover { translate: 0 -6px; }
.why-item:hover,
.project-card:hover {
  border-color: var(--rule);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.95),
              0 18px 40px rgba(19, 39, 63, 0.11);
}

/* Narrow screens: the copy takes the full width and the artwork holds its
   right side, darkened further by the overlay so the text stays readable. */
@media (max-width: 900px) {

}

/* ================================================================
   Service pages
   ================================================================ */
.service-page {
  /* The inner sections carry .section-deep, which sets light type — the hero
     does not, so without this it inherits the body's dark ink and disappears. */
  color: var(--navy);
}
.service-hero {
  /* Clears the fixed header, same as the case studies do. */
  padding: 190px 1.5rem 80px;
}
.service-headline {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.8rem, 5.6vw, 4.9rem);
  letter-spacing: -0.028em;
  line-height: 1.06;
  margin-bottom: 20px;
}
.service-subhead {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.9rem, 3.4vw, 2.6rem);
  letter-spacing: -0.026em;
  line-height: 1.12;
  margin-bottom: 20px;
}
.service-lead {
  font-size: clamp(1.2rem, 2.1vw, 1.55rem);
  /* The hero's paragraph is the headline's counterweight across the split, so
     it scales with it rather than sitting at body size. */
  font-weight: 400;
  line-height: 1.5;
  max-width: 42ch;
  margin: 0 auto 20px;
  opacity: 0.9;
}

/* The hero CTA's own entrance is delayed 2.45s to follow the homepage loading
   screen. These pages have no loader, so that delay would leave the buttons
   invisible on arrival — .reveal drives them here, as it does .case-cta-button. */
.service-page .hero-cta { animation: none; opacity: 1; }

/* ---------- "What we do" hub ----------
   The brand at the centre with four disciplines around it. Positioned as
   percentages of a fixed-ratio stage so the arrangement holds at any width,
   and it collapses to a plain list before the cards would start colliding. */
.hub {
  position: relative;
  width: 100%;
  margin: 26px auto 0;
  aspect-ratio: 1 / 0.70;
  /* The diagram is sized against its own width, not the viewport's, because it
     now sits in a column rather than across the page. Every measurement below
     is a share of that width with a floor, so it scales like a graphic instead
     of reflowing — and still stops shrinking before the labels stop reading. */
  container-type: inline-size;
}
.hub-ring {
  position: absolute;
  left: 50%; top: 50%;
  width: 62%; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  border: 1px solid var(--rule-diagram);
}
/* Four connectors from the core out to each card. */
.hub-spokes {
  position: absolute;
  left: 50%; top: 50%;
  width: 48%; aspect-ratio: 1;
  transform: translate(-50%, -50%);
  /* Each connector fades out as it leaves the core, so the lines read as
     emanating from the centre rather than as four drawn strokes. They start a
     little above the brief's flat 0.12 because they average out below it once
     the fade is taken into account. */
  /* Each connector still fades out as it leaves the core, so it reads as
     emanating from the centre — it just starts darker, since a line that fades
     averages well below whatever value it begins at. */
  background:
    linear-gradient(to top, rgba(19, 39, 63, 0.5), transparent) no-repeat 50% 0 / 1px 50%,
    linear-gradient(to bottom, rgba(19, 39, 63, 0.5), transparent) no-repeat 50% 100% / 1px 50%,
    linear-gradient(to left, rgba(19, 39, 63, 0.5), transparent) no-repeat 0 50% / 50% 1px,
    linear-gradient(to right, rgba(19, 39, 63, 0.5), transparent) no-repeat 100% 50% / 50% 1px;
}
.hub-core {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 24%; aspect-ratio: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: clamp(0.35rem, 1.2cqw, 0.7rem);
  border-radius: 50%;
  border: 1px solid var(--chocolate);
  /* Brown, so the centre reads as the hub rather than merging into the navy
     cards around it. The mark still has a dark field to sit on. */
  background: var(--chocolate);
  box-shadow: 0 18px 44px rgba(19, 39, 63, 0.16);
  /* The core is dark whatever the page is doing behind it. */
  color: var(--blanc);
}
.hub-core img { width: 32%; height: auto; }
.hub-core-name {
  font-size: clamp(0.55rem, 1.15cqw, 0.68rem);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  opacity: 0.75;
}
.hub-cards { position: absolute; inset: 0; list-style: none; margin: 0; }
.hub-card {
  position: absolute;
  display: flex; align-items: center; gap: clamp(0.6rem, 1.4cqw, 1rem);
  width: 44cqw; max-width: 44%;
  padding: clamp(0.7rem, 1.6cqw, 1.1rem) clamp(0.9rem, 2.2cqw, 1.5rem)
           clamp(0.7rem, 1.6cqw, 1.1rem) clamp(0.7rem, 1.6cqw, 1.1rem);
  border-radius: 999px;
  border: 1px solid var(--rule);
  /* Deeper than the 0.55 the brief names: where the layout stacks, the lowest
     card lands on the page's palest band, and at 0.55 its surface came out
     #6B89A8 — light type on that is 3.3:1. At 0.72 the card is dark enough to
     carry its own type wherever it falls, and still reads as glass. */
  background: var(--navy);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 18px 44px rgba(19, 39, 63, 0.30);
  text-align: left;
  /* The cards float over a ground that runs from navy to pale blue down the
     page, so they carry their own ink rather than inheriting the section's. */
  color: var(--navy);
}
.hub-top    { left: 50%; top: 0;    transform: translateX(-50%); }
.hub-bottom { left: 50%; bottom: 0; transform: translateX(-50%); }
.hub-left   { left: 0;   top: 50%;  transform: translateY(-50%); }
.hub-right  { right: 0;  top: 50%;  transform: translateY(-50%); }
/* The side cards share the centre line with the core, which is 27% of the stage
   wide. Half the stage, less half the core, less a gap, is the most they can be
   without running into it — the top and bottom cards clear it vertically and
   keep the roomier width. */
.hub-left,
.hub-right { max-width: 36%; }
.hub-icon {
  flex: 0 0 auto;
  width: clamp(2.2rem, 6.2cqw, 3.4rem); height: clamp(2.2rem, 6.2cqw, 3.4rem);
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--rule);
  background: rgba(19, 39, 63, 0.06);
  color: var(--navy);
}
.hub-icon svg { width: clamp(1rem, 2.7cqw, 1.5rem); height: clamp(1rem, 2.7cqw, 1.5rem); }
.hub-copy h4 {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(0.68rem, 1.45cqw, 0.82rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.4rem;
}
.hub-copy p { font-size: clamp(0.75rem, 1.65cqw, 0.9rem); line-height: 1.5; opacity: 0.85; }

/* ================================================================
   B2B Marketing — the positioning page
   ================================================================ */

/* One page-long gradient, same five brand colours, same rule as the homepage:
   no section paints its own background, so there are no edges to align. The
   stops sit at different percentages here only because the page is shorter and
   its sections fall in different places — the pale band is parked on the
   outcomes, which are typography on a light ground, and the ecosystem is kept
   in the deep half where its glass cards and hairlines have something to sit
   against. Move a stop here rather than giving a section a background. */
/* Wider than the rest of the site's containers: the pages composed in two
   columns need more than the measure that suits a single column of prose. */
.container-editorial { width: min(92%, 1340px); margin-inline: auto; }

.b2b-section { padding: 96px 1.5rem 104px; }

/* Ink follows the ground, because the ground moves. The page opens dark and
   runs pale from the outcomes on, so those two sections take the navy and
   everything above keeps the off-white. Off-white on var(--navy) is 3.1:1 and navy
   on var(--navy) is unreadable — neither ink works for the whole page.

   The closing section is navy too, which is the one place the layout revision
   forced a choice. The page is now short enough that returning the ground to
   var(--navy) before the CTA's copy would mean dropping most of the luminance
   range inside ~200px of padding — a hard band, the exact artefact this
   gradient exists to avoid. So the ground keeps descending gently through the
   CTA and resolves into the footer, and the CTA's ink goes navy to meet it.
   The button is its own white surface either way. */
.b2b-outcomes { color: var(--forma-navy); }
/* The approach tiles are the brown ones; the rest of the site's tiles are navy. */
.approach-tiles .why-item { background: var(--chocolate); }
/* Navy ink diluted by an eyebrow's usual 0.7 measures 4.5:1 or worse against
   these grounds — the dilution alone is what costs it. */
.b2b-outcomes .eyebrow,
.b2b-cta .eyebrow,
.b2b-cta .service-lead { opacity: 1; }

/* ---------- The two-column composition ----------
   Statement left, explanation right, with slightly more weight on the left.
   The divider is drawn on the right column so no section needs an element for
   it, and it is inset from the top and bottom rather than running edge to edge
   — a full-height rule would read as a table border. */
.b2b-split {
  --split-gap: clamp(40px, 5vw, 92px);
  display: grid;
  grid-template-columns: 54fr 46fr;
  gap: var(--split-gap);
  align-items: start;
}
.b2b-aside-col { position: relative; }
.b2b-aside-col::before {
  content: "";
  position: absolute;
  left: calc(var(--split-gap) / -2);
  top: 0.35em;
  bottom: 0.35em;
  width: 1px;
  background: currentColor;
  opacity: 0.2;
}
.b2b-split .service-lead { margin-left: 0; margin-right: 0; max-width: 40ch; }
/* The hero's left column runs much taller than its paragraph — eyebrow,
   three lines of headline, two buttons — so with the grid's default start
   alignment the paragraph sat high against the divider. The column fills the
   row instead and centres its copy, which also gives the rule the full height
   of the hero rather than just the paragraph's. */
.service-hero .b2b-split { align-items: stretch; }
.service-hero .b2b-aside-col {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.service-hero .service-lead {
  font-size: clamp(1.15rem, 2.1vw, 1.7rem);
  line-height: 1.45;
  max-width: 34ch;
}
.b2b-split .body-copy { max-width: 46ch; margin-bottom: 22px; }
.b2b-split .body-copy:last-child { margin-bottom: 0; }
.b2b-lead-col .hero-ctas { justify-content: flex-start; margin-top: 38px; }

/* The approach section gives the diagram the larger share and centres the two
   columns against each other, since the graphic is taller than its copy. */
.b2b-split--approach {
  --split-gap: clamp(56px, 7.5vw, 140px);
  /* The diagram carries this section, so it takes the larger share. The
     headline still fits on two lines at 36%. */
  grid-template-columns: 36fr 64fr;
  align-items: center;
}
/* The diagram is the tallest thing on the page and was sitting hard against
   both the divider and the sections either side of it. */
.b2b-approach { padding-top: 132px; padding-bottom: 144px; }

/* ---------- The ecosystem in its column ---------- */
.b2b-ecosystem { display: grid; }

/* The diagram's name is this section's headline now, and it is the only thing
   in the column beside the eyebrow, so it takes more size than a section
   subhead normally would. */
.b2b-ecosystem-headline {
  font-size: clamp(2.4rem, 4.5vw, 3.7rem);
  line-height: 1.08;
  /* The column sets the measure. A ch cap here was breaking it to three lines
     once the split gap widened and the column narrowed with it. */
  margin-bottom: 0;
}

/* ---------- Outcomes ---------- */
/* The tiles themselves are .service-item, shared with the homepage; only the
   spacing above them belongs to this page. */
.b2b-outcome-grid { margin-top: clamp(48px, 5vw, 76px); }

/* ---------- The closing CTA — the one centred section on the page ---------- */
/* The page closes on brown rather than trailing off into the white. */
.b2b-cta { padding-bottom: 120px; }
.b2b-cta .container-narrow { text-align: center; }
.b2b-cta .hero-ctas { margin-top: 6px; }

/* The column only gets comfortable for four cards around a centre once the
   container is near its cap: below about 1400px the side cards start crowding
   the core — French first, since its labels run longer. Under that the approach
   section stacks and the diagram takes the container instead, at roughly the
   same size the column would have given it and with far more room around it. */
@media (max-width: 1400px) {
  .b2b-split--approach { grid-template-columns: 1fr; }
  .b2b-split--approach .b2b-aside-col::before { display: none; }
  .b2b-ecosystem { margin-top: 26px; }
  .b2b-ecosystem .hub { max-width: 860px; margin-inline: auto; }
}

/* ================================================================
   LinkedIn Management — the service page
   ================================================================ */

/* The page's own stops on the same five-colour, page-long gradient. Solved
   against where this page's text actually falls; see the B2B page for the same
   reasoning. */
.linkedin-section { padding: 104px 1.5rem 112px; }

/* Ink follows the ground: dark at both ends, pale through the middle. The
   closing section is absent here because its content lives inside a dark glass
   panel that carries its own. */

/* The section number, in the serif italic the site uses for editorial marks. */

/* ---------- 01 — Hero ---------- */
/* The statement is the hero's visual headline; the H1 above it is the page's
   name, kept small because the sentence is what should be read first. */
/* A shade smaller than the B2B hero's headline: here it shares the column with
   a label, a paragraph and a button, and at the larger size it broke
   "conversations / happen." across two lines. */
.linkedin-statement {
  font-size: clamp(2.1rem, 3.9vw, 3.4rem);
  margin-bottom: 24px;
}
.linkedin-hero .hero-ctas { justify-content: flex-start; margin-top: 34px; }

/* ---------- Hero visual — abstract profile and conversation ---------- */
/* Bars standing in for text: the visual suggests a conversation without
   inventing copy that would read as real content. */
/* The thread the cards hang from. */

/* ---------- 02 — Three statements, rules instead of cards ---------- */
.linkedin-statements {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(28px, 4vw, 64px);
  margin-top: clamp(56px, 6vw, 86px);
}
.linkedin-statements li {
  padding-top: 30px;
  border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}
.linkedin-statements h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  letter-spacing: -0.02em;
  margin-bottom: 14px;
}
.linkedin-statements p { font-size: 15px; line-height: 1.7; max-width: 34ch; }

/* ---------- 03 — Three parts: the homepage tile, three across ---------- */
.linkedin-parts {
  grid-template-columns: repeat(3, 1fr);
  margin-top: clamp(48px, 5vw, 76px);
}

/* ---------- 04 — The rail ---------- */
.method-rail {
  position: relative;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: clamp(16px, 2vw, 34px);
  margin-top: clamp(64px, 7vw, 104px);
  padding-top: 34px;
  list-style: none;
}
/* One line through all five stages rather than four separate connectors. */
.method-rail::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(90deg,
      color-mix(in srgb, currentColor 8%, transparent),
      color-mix(in srgb, currentColor 34%, transparent) 20%,
      color-mix(in srgb, currentColor 34%, transparent) 80%,
      color-mix(in srgb, currentColor 8%, transparent));
}
.method-stage { position: relative; }
.method-stage-mark {
  position: absolute;
  left: 0; top: -37px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.6;
}
.method-stage h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
  margin-bottom: 10px;
}
.method-stage p { font-size: 14px; line-height: 1.6; }

/* ---------- 05 — The index ---------- */


.linkedin-cta { padding-bottom: 132px; text-align: center; }
/* ================================================================
   Ink rhythm
   ================================================================ */
/* Headlines navy, everything that supports them brown. Not alternating any
   more — one rule for the whole site. */
.hero-headline,
.approach-headline,
.services-headline,
.projects-headline,
.service-headline,
.service-subhead,
.b2b-ecosystem-headline,
.linkedin-statement,
.section-title,
.case-headline,
.case-heading,
.case-cta-headline,
h1, h2 { color: var(--navy); }

/* Subheads, leads, body and small labels: brown. */
.body-copy,
.service-lead,
.services-sub,
.projects-sub,
.approach-statement,
.hero-sub,
.eyebrow,
.hero-eyebrow,
.section-label,
.case-body,
h3, h4 { color: var(--chocolate); }

/* ---------- Surfaces painted in a brand colour ----------
   Navy heroes, the Featured Work section, every tile, and the brown contact
   panel. Anything inside them takes the light ink, headings included — a navy
   headline on a navy tile is not a headline. */
.hero,
.service-hero,
.case-hero,
.section-projects {
  background: var(--navy);
}
.contact-tile,
/* Both service pages close on brown rather than trailing off into the white. */
.b2b-cta,
.linkedin-cta { background: var(--chocolate); }

.hero, .hero *,
.service-hero, .service-hero *,
.section-projects, .section-projects *,
.case-hero, .case-hero *,
.contact-tile, .contact-tile *,
.service-item, .service-item *,
.why-item, .why-item *,
.client-item, .client-item *,
.hub-card, .hub-card *,
.b2b-cta, .b2b-cta *,
.linkedin-cta, .linkedin-cta * { color: var(--blanc); }

/* Borders and rules inside those surfaces have to invert with the ink. */

.service-item,
.why-item,
.client-item,
.hub-card,
.contact-tile {
  border-color: rgba(251, 250, 247, 0.16);
  box-shadow: 0 14px 34px rgba(19, 39, 63, 0.12);
}
.service-item:hover,
.why-item:hover,
.client-item:hover,
.project-card:hover {
  border-color: rgba(251, 250, 247, 0.34);
  box-shadow: 0 20px 44px rgba(19, 39, 63, 0.18);
}

/* Featured Work sits on navy, so its cards lift off it rather than repeat it. */
.section-projects .project-card {
  background: rgba(251, 250, 247, 0.07);
  border-color: rgba(251, 250, 247, 0.16);
}
.section-projects .project-media,
.section-projects .project-media-future { background: rgba(251, 250, 247, 0.08); }
.section-projects .project-preview {
  background: rgba(19, 39, 63, 0.72);
  color: var(--blanc);
}

/* The contact panel is brown: its fields and button invert with it. */
.contact-tile .field input,
.contact-tile .field select,
.contact-tile .field textarea {
  background: rgba(251, 250, 247, 0.10);
  border-color: rgba(251, 250, 247, 0.22);
  color: var(--blanc);
}
.contact-tile .field input::placeholder,
.contact-tile .field textarea::placeholder { color: rgba(251, 250, 247, 0.55); }
.contact-tile .field input:focus,
.contact-tile .field select:focus,
.contact-tile .field textarea:focus {
  border-color: var(--blanc);
  box-shadow: 0 0 0 3px rgba(251, 250, 247, 0.16);
}
.contact-tile .btn-submit,
.contact-tile .btn-submit * { color: var(--navy); }
.contact-tile .btn-submit { background: var(--blanc); }
.contact-tile .btn-submit:hover:not(:disabled),
.contact-tile .btn-submit:hover:not(:disabled) * { color: var(--blanc); }
.contact-tile .btn-submit:hover:not(:disabled) { background: var(--navy); }

/* Primary buttons on a navy ground invert the same way. */
.hero .hero-cta,
.hero .hero-cta *,
.service-hero .hero-cta,
.service-hero .hero-cta *,
.section-projects .hero-cta,
.section-projects .hero-cta *,
.b2b-cta .hero-cta,
.b2b-cta .hero-cta *,
.linkedin-cta .hero-cta,
.linkedin-cta .hero-cta * { color: var(--navy); }
.hero .hero-cta,
.service-hero .hero-cta,
.section-projects .hero-cta,
.b2b-cta .hero-cta,
.linkedin-cta .hero-cta {
  background: var(--blanc);
  border-color: var(--blanc);
}
.hero .hero-cta:hover,
.hero .hero-cta:hover *,
.service-hero .hero-cta:hover,
.service-hero .hero-cta:hover *,
.hero .hero-cta:focus-visible,
.service-hero .hero-cta:focus-visible { color: var(--blanc); }
.hero .hero-cta:hover,
.service-hero .hero-cta:hover,
.hero .hero-cta:focus-visible,
.service-hero .hero-cta:focus-visible {
  background: var(--chocolate);
  border-color: var(--chocolate);
}
/* On the brown closing section the hover goes navy, not brown on brown. */
.b2b-cta .hero-cta:hover,
.b2b-cta .hero-cta:hover *,
.b2b-cta .hero-cta:focus-visible,
.linkedin-cta .hero-cta:hover,
.linkedin-cta .hero-cta:hover *,
.linkedin-cta .hero-cta:focus-visible {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--blanc);
}
.hero .hero-cta-ghost,
.service-hero .hero-cta-ghost {
  background: transparent;
  color: var(--blanc);
  border-color: rgba(251, 250, 247, 0.55);
}
.hero .hero-cta-ghost:hover,
.hero .hero-cta-ghost:hover *,
.service-hero .hero-cta-ghost:hover,
.service-hero .hero-cta-ghost:hover *,
.hero .hero-cta-ghost:focus-visible,
.service-hero .hero-cta-ghost:focus-visible {
  background: var(--blanc);
  color: var(--navy);
  border-color: var(--blanc);
}

/* The tags in a case hero sit on navy, so their hairline inverts with the ink. */
.case-hero .case-tags li { border-color: rgba(251, 250, 247, 0.30); }

/* The closing CTA is a brown tile rather than an open section, matching the
   closing panels on the other pages. */
.case-cta-panel {
  position: relative;
  text-align: center;
  padding: clamp(56px, 7vw, 104px) clamp(28px, 5vw, 90px);
  border-radius: 34px;
  border: 1px solid rgba(251, 250, 247, 0.16);
  background: var(--chocolate);
  box-shadow: 0 12px 30px rgba(19, 39, 63, 0.12);
  transition: transform 420ms var(--ease-motion),
              border-color 420ms var(--ease-motion),
              box-shadow 420ms var(--ease-motion);
}
.case-cta-panel::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(158deg,
      rgba(255, 255, 255, 0.17) 0%,
      rgba(255, 255, 255, 0.05) 32%,
      transparent 58%);
  pointer-events: none;
}
.case-cta-panel > * { position: relative; z-index: 1; }
.case-cta-panel:hover {
  transform: translateY(-6px);
  border-color: rgba(251, 250, 247, 0.32);
  box-shadow: 0 18px 40px rgba(19, 39, 63, 0.18);
}
.case-cta-panel,
.case-cta-panel * { color: var(--blanc); }
/* The button inverts inside it, as it does in every other painted surface. */
.case-cta-panel .hero-cta,
.case-cta-panel .hero-cta * { color: var(--navy); }
.case-cta-panel .hero-cta {
  background: var(--blanc);
  border-color: var(--blanc);
}
.case-cta-panel .hero-cta:hover,
.case-cta-panel .hero-cta:hover *,
.case-cta-panel .hero-cta:focus-visible {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--blanc);
}
.case-cta-panel .case-cta-sub { max-width: 46ch; }

/* ================================================================
   Mobile
   ================================================================ */
@media (max-width: 768px) {
  .clients-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 600px) {
  .hero-ctas { flex-direction: column; align-items: stretch; width: 100%; }
  .hero-cta, .btn-submit { width: 100%; min-height: 50px; justify-content: center; }
}

@media (max-width: 720px) {
  /* Mobile: about 35% less travel again, and the diagram's parts stop scaling
     in — at this size they are a plain list and a scale reads as a wobble. */
  :root { --motion-rise: 18px; --motion-shift: 12px; }
  .js .hub-card.in-view,
  .js .hub-core.in-view { --reveal-from: 1; }
  .nav-toggle { display: block; }
  .nav-menu {
    position: fixed; inset: 0;
    flex-direction: column;
    align-items: center; justify-content: center;
    gap: 2.5rem;
    background: var(--navy);
    opacity: 0; visibility: hidden;
    transition: opacity var(--t-slow) var(--ease), visibility var(--t-slow) var(--ease);
  }
  /* The scrolled bar carries a backdrop-filter, and a non-none backdrop-filter
     makes an element the containing block for its fixed-position descendants.
     The menu is a fixed child of the bar, so once you had scrolled it stopped
     resolving against the viewport and collapsed into the bar's own 84px box —
     which is why the menu only worked at the very top of the page. The bar
     drops the filter while the menu is open; the full-screen overlay covers it
     anyway, so there is nothing left for it to blur. */
  .site-header:has(.nav-menu.open) {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: transparent;
    border-bottom-color: transparent;
  }
  .nav-menu.open { opacity: 1; visibility: visible; }
  /* The overlay is navy. Without this the links keep the dark ink they use on
     the scrolled bar and disappear into it — which is the menu "bugging" once
     you have scrolled before opening it. */
  .nav-menu.open a,
  .nav-menu.open .nav-services-toggle,
  .nav-menu.open .nav-submenu a { color: var(--blanc); }
  .nav-menu.open .nav-lang { border-color: rgba(251, 250, 247, 0.45); }
  .nav-menu.open .nav-submenu a:hover { background: rgba(251, 250, 247, 0.12); }
  .site-header.scrolled .nav-toggle span { background: var(--navy); }
  /* :has, because the toggle precedes the menu in the DOM — a sibling
     combinator cannot reach backwards. */
  .site-header:has(.nav-menu.open) .nav-toggle span { background: var(--blanc); }
  .nav-menu a { font-size: 1rem; }

  .services-grid { grid-template-columns: 1fr; gap: 18px; }
  .services-section { padding: 110px 1.5rem 130px; }
  .service-item { padding: 24px 22px 26px; }
  .service-number { margin-bottom: 18px; }
  .service-hero { padding: 150px 1.5rem 50px; }
  .approach-section { padding: 110px 1.5rem 120px; }
  .approach-statement { max-width: none; }
  /* The hub needs width to keep four cards clear of a centre. Below this it
     unrolls into the same system read vertically: the core still leads it, the
     cards sit under it in order, and the orbit and connectors — which only
     mean anything in the round — are dropped rather than squashed. */
  .hub { aspect-ratio: auto; margin-top: 32px; display: grid; justify-items: center; }
  .hub-ring, .hub-spokes { display: none; }
  .hub-core {
    position: static; transform: none;
    width: 11rem; margin-bottom: 26px;
  }
  .hub-cards { position: static; display: grid; gap: 14px; width: 100%; }
  .hub-card {
    position: static; transform: none;
    width: 100%; max-width: none;
    border-radius: 18px;
    align-items: flex-start;
  }
  .b2b-section { padding: 76px 1.5rem 84px; }
  /* The split unrolls; the divider only means anything between two columns. */
  .b2b-split { grid-template-columns: 1fr; gap: 34px; }
  .b2b-aside-col::before { display: none; }
  .b2b-split .service-lead,
  .b2b-split .body-copy { max-width: none; }
  .b2b-lead-col .hero-ctas { margin-top: 30px; }
  .b2b-ecosystem { margin-top: 8px; }
  .b2b-outcome-grid { margin-top: 36px; }

  /* LinkedIn page: every row becomes a column, and the rail stands up. */
  .linkedin-section { padding: 76px 1.5rem 84px; }
  .linkedin-statement { max-width: none; }
  .linkedin-statements,
  .linkedin-parts,
  .linkedin-statements { gap: 26px; margin-top: 40px; }
  .method-rail {
    grid-template-columns: 1fr;
    gap: 30px;
    padding-top: 0;
    padding-left: 26px;
  }
  /* The line runs down the side instead of across the top. */
  .method-rail::before {
    left: 0; right: auto; top: 0; bottom: 0;
    width: 1px; height: auto;
    background: linear-gradient(180deg,
        color-mix(in srgb, currentColor 8%, transparent),
        color-mix(in srgb, currentColor 34%, transparent) 12%,
        color-mix(in srgb, currentColor 34%, transparent) 88%,
        color-mix(in srgb, currentColor 8%, transparent));
  }
  .method-stage-mark { left: -29px; top: 0.45rem; }
  .nav-has-menu { width: 100%; text-align: center; }
  .nav-services-toggle { justify-content: center; width: 100%; }
  .nav-submenu {
    position: static; transform: none; min-width: 0;
    margin: 0.5rem 0 0; padding: 0.35rem 0;
    background: none; border: 0; box-shadow: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    opacity: 1; visibility: visible; pointer-events: auto;
    display: none;
  }
  .nav-has-menu.open .nav-submenu { display: grid; transform: none; }
  .services-section { padding-top: 80px; padding-bottom: 80px; }
  .body-copy { font-size: 15px; }
  .service-item { padding: 20px 18px 22px; }
  .projects-grid { grid-template-columns: 1fr; gap: 60px; }
  .section-projects { padding: 90px 1.5rem; }
  .case-hero { padding: 150px 1.5rem 40px; }
  .case-section { padding: 45px 1.5rem; }
  .form-grid { grid-template-columns: 1fr; }
  .contact-tile { grid-template-columns: 1fr; padding: 28px 22px 32px; gap: 24px; }
  .footer-links { flex-direction: column; gap: 1rem; }

  .hero-sub { font-size: 14px; }
  /* Two 200px pills won't fit side by side — stack them full-width. */
  .hero-ctas { flex-direction: column; width: 100%; max-width: 280px; gap: 10px; }
  .hero-ctas .hero-cta { width: 100%; margin-top: 0; }
  .hero-ctas { margin-top: 22px; }
  .why-grid { grid-template-columns: 1fr; gap: 32px; margin-top: 40px; }
  .clients-grid { grid-template-columns: 1fr; gap: 16px; margin-top: 36px; }
  .clients-section { padding-top: 80px; padding-bottom: 80px; }
  .client-item { min-height: 0; padding: 20px 18px; }
  .services-sub { margin: -20px 0 34px; }
}
@media (min-width: 721px) and (max-width: 1024px) {
  /* Tablet: about 20% less travel, from the tokens, so no rule restates it. */
  :root { --motion-rise: 22px; --motion-shift: 16px; }
  .services-grid { gap: 24px 32px; }
  .services-section { padding-top: 100px; padding-bottom: 100px; }
  .body-copy { font-size: 15px; }
}
@media (min-width: 721px) and (max-width: 1024px) {
  /* Two columns held, spacing reduced. The approach section is the exception —
     see the stacking rule above. */
  .b2b-section { padding: 84px 1.5rem 92px; }
  .b2b-split { --split-gap: 40px; }

  .projects-grid { grid-template-columns: repeat(2, 1fr); gap: 40px; }
  .why-grid { grid-template-columns: repeat(2, 1fr); gap: 36px; }
  .clients-grid { grid-template-columns: repeat(2, 1fr); }
}

/* ================================================================
   Reduced motion — calm by default, still for those who ask
   ================================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .nav-brand { animation: none; }
  #loader { display: none; }
  .hero-headline, .hero-cta { animation: none; opacity: 1; }
  .hero-sub { animation: none; opacity: 0.8; }
  .js .reveal,
  .js .reveal-lg,
  .js .reveal-left,
  .js .reveal-right,
  .js .reveal-pop,
  .js .reveal-rise,
  .js .reveal-fade,
  .js .reveal-scale {
    opacity: 1;
    animation: none !important;
    transition: none;
  }
  /* transform: none only for the variants whose entrance used transform. The
     fade and scale variants exist precisely because their transform is their
     position — clearing it here would throw the diagram's core, orbit and
     cards off their axes, which is the bug the split was introduced to fix. */
  .js .reveal,
  .js .reveal-lg,
  .js .reveal-left,
  .js .reveal-right,
  .js .reveal-pop,
  .js .reveal-rise { transform: none; }
  .js .reveal-scale { scale: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
