/* ==========================================================================
   Harton Ltd — civil engineers & road contractors
   Design system lifted from the Buildza Framer template: Manrope headings,
   Inter body, monochrome surfaces, one navy accent, pill buttons, soft radii.
   Every value below was measured off the reference at 1440px, not eyeballed.
   ========================================================================== */

/* --- Tokens --------------------------------------------------------------- */

:root {
  /* Ink and text. The reference never uses pure black for type. */
  --ink: #1c1c1c;
  --body: #525252;
  --muted: #828282;

  /* Surfaces */
  --white: #ffffff;
  --surface: #fafafa;
  --surface-2: #f5f5f5;
  --line: rgba(28, 28, 28, 0.1);
  --line-strong: rgba(28, 28, 28, 0.16);

  /* The single accent, sampled off the tick in the supplied logo — #0830a0 is
     the dominant blue across ~23k pixels of it. Against white it measures
     10.82:1, so it carries text and white-on-blue equally well at any size.
     (The template's own #1e365d navy measured 10.4:1 and works just as well;
     it is one line to swap back if the brand blue reads too loud.) */
  --navy: #0830a0;
  --navy-hover: #06246f;
  --navy-tint: rgba(8, 48, 160, 0.08);

  /* Type */
  --display: "Manrope", ui-sans-serif, system-ui, sans-serif;
  --sans: "Inter", ui-sans-serif, system-ui, sans-serif;

  /* Rhythm. The reference runs 62px section padding and a 1150px content
     column inside a 1200px container with 25px gutters. */
  --container: 1200px;
  --gutter: 25px;
  --section-y: 62px;

  /* Radii. Squared off — cards, panels, images and inputs all sit on hard
     corners, which suits a civil engineering firm better than the softened
     look the template shipped with.

     The pill is kept for BUTTONS, badges and tags only. Those are controls
     and labels rather than surfaces; squaring them too turns every button
     into a grey rectangle and takes the last bit of warmth out of the page.
     Set --r-pill to 0 as well if fully square controls are wanted. */
  --r-pill: 999px;
  --r-card: 0;
  --r-lg: 0;
  --r-xl: 0;

  /* The one exception to the square corners: the outer ends of the split hero
     band, which round so the pair reads as a single hero shape. */
  --r-hero: 24px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* --- Reset ---------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--white);
  color: var(--body);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: -0.045em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg,
video {
  display: block;
  max-width: 100%;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

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

/* --- Type ----------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--display);
  color: var(--ink);
  font-weight: 500;
  /* The reference's signature: very tight tracking on large display type.
     It is what stops Manrope reading as a default system font. */
  letter-spacing: -0.055em;
}

h1 {
  font-size: clamp(2.25rem, 1.4rem + 3.4vw, 3.125rem); /* 36 → 50px */
  line-height: 1.25;
  letter-spacing: -0.05em;
}

h2 {
  font-size: clamp(2rem, 1.35rem + 2.6vw, 2.875rem); /* 32 → 46px */
  line-height: 1.35;
}

h3 {
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem); /* 20 → 24px */
  line-height: 1.35;
  letter-spacing: -0.04em;
}

p {
  margin: 0;
}

.lede {
  font-size: 17px;
  line-height: 1.55;
  color: var(--body);
}

.small {
  font-size: 14px;
  line-height: 1.4;
  letter-spacing: -0.04em;
}

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

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--section-y);
}

.section--tight {
  padding-block: 48px;
}

/* The eyebrow + heading + optional action that opens nearly every section. */
.section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  margin-bottom: 48px;
}

.section-head__text {
  max-width: 620px;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.eyebrow::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--navy);
}

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

.eyebrow--light::before {
  background: var(--white);
}

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

/* The template's buttons are 41px pills whose label slides up and is replaced
   by a copy of itself on hover. Both labels live in the markup; the wrapper
   clips. Height is locked to the line box so the swap cannot jitter. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 41px;
  padding: 0 18px 0 16px;
  border-radius: var(--r-pill);
  font-size: 16px;
  letter-spacing: -0.04em;
  line-height: 1;
  white-space: nowrap;
  transition:
    background-color 0.3s var(--ease),
    color 0.3s var(--ease),
    transform 0.3s var(--ease);
}

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

.btn__label {
  position: relative;
  display: block;
  height: 1.2em;
  overflow: hidden;
}

.btn__label span {
  display: block;
  height: 1.2em;
  line-height: 1.2em;
  transition: transform 0.4s var(--ease);
}

.btn:hover .btn__label span {
  transform: translateY(-1.2em);
}

.btn__icon {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex: none;
  transition:
    background-color 0.3s var(--ease),
    transform 0.3s var(--ease);
}

.btn:hover .btn__icon {
  transform: rotate(45deg);
}

.btn__icon svg {
  width: 11px;
  height: 11px;
}

.btn--navy {
  background: var(--navy);
  color: var(--white);
}

.btn--navy .btn__icon {
  background: rgba(255, 255, 255, 0.18);
}

.btn--navy:hover {
  background: var(--navy-hover);
}

.btn--white {
  background: var(--white);
  color: var(--ink);
}

.btn--white .btn__icon {
  background: rgba(28, 28, 28, 0.08);
}

.btn--ghost {
  background: transparent;
  color: var(--white);
  border: 1px solid rgba(255, 255, 255, 0.35);
}

.btn--ghost .btn__icon {
  background: rgba(255, 255, 255, 0.18);
}

.btn--ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

.btn--outline {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line-strong);
}

.btn--outline .btn__icon {
  background: rgba(28, 28, 28, 0.06);
}

.btn--outline:hover {
  background: var(--surface);
}

/* A quieter text link with a travelling arrow, used inside cards. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.link-arrow svg {
  width: 13px;
  height: 13px;
  transition: transform 0.3s var(--ease);
}

.link-arrow:hover svg,
a:hover .link-arrow svg {
  transform: translate(3px, -3px);
}

/* --- Navbar --------------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--white);
  padding-block: 12px;
  transition: box-shadow 0.3s var(--ease);
}

.nav.is-stuck {
  box-shadow: 0 1px 0 var(--line);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 58px;
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

/* The logo is a wide lockup (roughly 4:1), so it is sized by height and left
   to find its own width. `width`/`height` attributes stay on the <img> for the
   aspect ratio, which is what stops the bar jumping as it loads. */
.brand-logo {
  height: 30px;
  width: auto;
}

.footer__brand .brand-logo {
  height: 34px;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 30px;
}

.nav__links a {
  position: relative;
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
  padding-block: 4px;
}

.nav__links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after {
  transform: scaleX(1);
}

.nav__actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}

.nav__toggle {
  display: none;
  width: 41px;
  height: 41px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  place-items: center;
}

.nav__toggle svg {
  width: 17px;
  height: 17px;
}

/* --- Hero ----------------------------------------------------------------- */

/* The card sits in equal whitespace: 36px between the bottom of the nav's
   logo and the top of the card, and 36px between the bottom of the card and
   the "Accredited…" line. Those are the two edges you actually see.

   Neither figure is this element's padding, which is why it cannot be set by
   eye and why the values look uneven:

     above = 12 (.nav padding-bottom)
           +  8.5 (slack — the 41px logo inside the bar's 58px row)
           + 15.5 (.hero padding-top)          = 36
     below = 24 (.hero padding-bottom)
           + 12 (.partners padding-top)        = 36

   The 8.5px of slack is the trap: setting this element's own padding to the
   same value top and bottom looks correct in the stylesheet and lands 8.5px
   out on screen. Measure card-edge to text-edge, not padding to padding.
   Change any of those five numbers and the balance goes. */
.hero {
  padding: 15.5px var(--gutter) 24px;
}

.hero__card {
  position: relative;
  max-width: 1150px;
  margin-inline: auto;

  /* The reference's hero is a flat 700px, which on a normal laptop reaches
     past the fold and leaves nothing below it visible — the page looks like
     it ends at the headline. Height is measured against the viewport instead,
     reserving ~250px for the bar, the card's own margins and a deliberate
     peek of the accreditations strip, so there is always something below the
     fold telling you to scroll.

     `min-height` rather than `height`, so the box still grows if the copy
     needs it rather than clipping. The `vh` line is a fallback for browsers
     without `svh`; `svh` is the one that matters on a phone, where `vh` is
     measured against the URL bar's collapsed state and overshoots. */
  min-height: clamp(440px, calc(100vh - 250px), 620px);
  min-height: clamp(440px, calc(100svh - 250px), 620px);
  border-radius: var(--r-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 32px 32px 48px;
  isolation: isolate;
  /* Fallback ground so the hero never renders as a white hole while the
     photograph is still loading or missing. */
  background: var(--navy);
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The scrim is DIAGONAL, not a simple top-to-bottom wash, and that is the
   whole point of it.

   A vertical gradient has to darken the entire width of the card to protect
   text that only occupies the left half — so the sky and the road on the
   right, which is most of the photograph, get flattened along with it. This
   runs bottom-left to top-right instead: dense where the headline and the
   sunlit machine are, almost clear over the sky. Measured against the real
   composited pixels, it beats the vertical version on both counts at once —
   headline 5.72:1 against 4.97:1, and the top-right of the picture 40%
   brighter (103 vs 73 mean luminance).

   The faint vertical layer on top is just a floor, stopping the very bottom
   edge going pale where the diagonal has run out.

   Re-solve after any change to the photograph OR to the hero's height or
   aspect. That second one has already caught us once: shortening the card to
   clear the fold changed the `object-fit: cover` crop, kept more bright sky,
   and dropped the headline to 2.41:1 with the picture untouched. Nothing
   warns you — it still looks broadly fine. The method is in CLAUDE.md. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(
      to top,
      rgba(12, 16, 24, 0.18) 0%,
      rgba(12, 16, 24, 0.08) 60%,
      rgba(12, 16, 24, 0.04) 100%
    ),
    linear-gradient(
      to top right,
      rgba(12, 16, 24, 0.96) 0%,
      rgba(12, 16, 24, 0.86) 50%,
      rgba(12, 16, 24, 0.32) 82%,
      rgba(12, 16, 24, 0.06) 100%
    );
}

/* Takes an element out of the painted page while leaving it in the
   accessibility tree and in the document for search engines. Used for the
   homepage <h1>: the split hero has no headline of its own, and a page with
   no <h1> at all leaves a screen reader with nothing announcing what the
   site is. The clip-path pair covers older engines alongside `clip`. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  white-space: nowrap;
  border: 0;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
}

/* --- Split hero -----------------------------------------------------------
   Two panels, one per audience, so a visitor self-selects before scrolling
   rather than reading three paragraphs to find out whether this firm does
   their kind of work.

   There is no headline above them by design. The panels carry their own
   headings, and the page's <h1> is visually hidden — see .visually-hidden. */

/* The two panels butt together with no gap and round only their OUTER
   corners, so the pair reads as one hero band split down the middle rather
   than as two tiles. The seam between the blue and the orange is the point.

   Keyed off :first-child / :last-child rather than the colour modifiers, so
   swapping the panel order in the HTML cannot leave the rounding on the
   wrong side. */
.hero-split__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0;
  max-width: 1150px;
  margin-inline: auto;
}

.hero-split__grid > .hero-panel:first-child {
  border-radius: var(--r-hero) 0 0 var(--r-hero);
}

.hero-split__grid > .hero-panel:last-child {
  border-radius: 0 var(--r-hero) var(--r-hero) 0;
}

/* Lifting one panel on hover would tear the seam open, so the pair scales the
   picture instead and the box itself stays put. */
.hero-panel:hover {
  transform: none;
}

.hero-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* The floor is the number that matters, and it is solved rather than
     chosen. Everything between the top of the viewport and the marquee is
     fixed: 82px bar + 15.5px hero padding + panel + 24px hero padding + 12px
     strip padding + 26px label + 26px label margin. Leaving ~30px of
     scrolling logos visible on a 675px window puts the ceiling on the panel
     at about 455px — so that is the floor, and taller screens get more. Go
     past it and the strip drops below the fold, which was the whole reason
     the hero was shortened in the first place. */
  min-height: clamp(455px, calc(100vh - 220px), 640px);
  min-height: clamp(455px, calc(100svh - 220px), 640px);
  padding: 28px;
  border-radius: var(--r-lg);
  overflow: hidden;
  isolation: isolate;
  background: var(--ink);
  color: var(--white);
  transition: transform 0.5s var(--ease);
}

.hero-panel:hover {
  transform: translateY(-3px);
}

.hero-panel__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.8s var(--ease);
}

.hero-panel:hover .hero-panel__media {
  transform: scale(1.04);
}

/* Vertical rather than the diagonal used on the full-width hero: these panels
   are close to portrait, so a diagonal runs out under the text with nothing
   to spare on the right. Same reasoning as the phone breakpoint.

   The dense band runs unusually high — 0.88 all the way to 55% — because the
   binding constraint here is the EYEBROW, not the heading. Content is
   bottom-aligned, so the small 16px label ends up highest in the panel, in
   the thinnest part of the scrim: it measured 4.11:1 while the heading below
   it was at 6.2:1 and the body copy at 12.5:1. Raising the band puts the
   eyebrow at 6.7:1 on both pictures.

   Measured on both panel images, which differ: a sunlit brick house and a
   machine against sky. Re-solve if either is replaced. */
.hero-panel__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to top,
    rgba(12, 16, 24, 0.95) 0%,
    rgba(12, 16, 24, 0.88) 55%,
    rgba(12, 16, 24, 0.44) 82%,
    rgba(12, 16, 24, 0.36) 100%
  );
}

/* Colour per audience. Blue is the commercial panel because it is the logo's
   own blue and reads institutional; orange is the domestic panel — warmer for
   a homeowner, and still a works colour rather than a decorative one.

   Both keep a near-black foot and carry the colour in the UPPER half. That is
   not a stylistic choice: the text sits at the bottom, and tinting a scrim
   toward a saturated hue LIGHTENS it, so colour where the words are costs
   contrast directly. Dark at the bottom, coloured at the top, and the panel
   still reads unmistakably blue or orange because the tinted half is the
   larger one. Re-measured after tinting — see the figures below. */
.hero-panel--commercial .hero-panel__scrim {
  background: linear-gradient(
    to top,
    rgba(3, 9, 28, 0.96) 0%,
    rgba(6, 22, 74, 0.87) 55%,
    rgba(12, 58, 190, 0.6) 82%,
    rgba(18, 76, 220, 0.58) 100%
  );
}

/* The orange needs more saturation than looked right on paper. The house in
   this panel is red brick, so a gentle warm wash has nothing to contrast
   against and collapses into one hue — the first attempt averaged RGB(136,
   84, 55) across its top half, which is terracotta, and read as a sepia photo
   filter rather than a deliberate colour. Pushed until it clears the brick. */
.hero-panel--home .hero-panel__scrim {
  background: linear-gradient(
    to top,
    rgba(24, 10, 3, 0.96) 0%,
    rgba(72, 26, 4, 0.87) 55%,
    rgba(214, 80, 10, 0.6) 82%,
    rgba(240, 104, 18, 0.6) 100%
  );
}

.hero-panel h2 {
  color: var(--white);
  font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2rem);
  line-height: 1.2;
  margin-bottom: 10px;
}

.hero-panel > p {
  font-size: 16px;
  line-height: 1.5;
  letter-spacing: -0.04em;
  color: rgba(255, 255, 255, 0.86);
  margin-bottom: 20px;
  max-width: 42ch;
}

.hero-panel .eyebrow {
  margin-bottom: 10px;
}

.hero-panel .btn {
  align-self: flex-start;
}

/* The whole panel is clickable; the pill is the visible affordance. The link
   is stretched over the panel rather than wrapping it, so the pill keeps its
   own hover state and the heading stays a heading. */
.hero-panel__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.hero__rating {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  /* Dark rather than the white-tinted fill this started as: at 14px the pill
     is the smallest white text on the photograph, and a white wash lightens
     its own backdrop, working against the very thing it is there to help. */
  background: rgba(12, 16, 24, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(10px);
  color: var(--white);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.04em;
}

.hero__rating strong {
  font-weight: 600;
}

.hero__body {
  max-width: 760px;
  color: var(--white);
}

.hero__body h1 {
  color: var(--white);
  margin-bottom: 18px;
}

.hero__body p {
  font-size: 18px;
  line-height: 1.4;
  letter-spacing: -0.04em;
  color: rgba(255, 255, 255, 0.86);
  max-width: 560px;
}

.hero__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 26px;
}

/* --- Partners / accreditations marquee ------------------------------------ */

/* Asymmetric on purpose. The 12px top is half of the hero's 32px bottom gap
   (see .hero) — pulling the strip up close so it reads as attached to the
   hero and shows sooner above the fold. The full 48px stays below, to
   separate it from the section that follows. Do not "even these up". */
.partners {
  padding: 12px 0 48px;
}

.partners__label {
  text-align: center;
  font-size: 17px;
  letter-spacing: -0.045em;
  color: var(--ink);
  margin-bottom: 26px;
}

/* Masked at both edges so items fade rather than getting cut off. */
.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    to right,
    transparent,
    #000 12%,
    #000 88%,
    transparent
  );
  mask-image: linear-gradient(
    to right,
    transparent,
    #000 12%,
    #000 88%,
    transparent
  );
}

.marquee__track {
  display: flex;
  width: max-content;
  gap: 56px;
  animation: marquee 34s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

@keyframes marquee {
  /* The track holds two identical copies, so travelling exactly half its
     width lands on a seamless loop point. */
  to {
    transform: translateX(-50%);
  }
}

.marquee__item {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.05em;
  color: var(--ink);
  opacity: 0.55;
  white-space: nowrap;
  transition: opacity 0.3s var(--ease);
}

.marquee__item:hover {
  opacity: 1;
}

.marquee__item svg {
  width: 20px;
  height: 20px;
  flex: none;
}

/* --- Intro: two-column grid + capability cards ---------------------------- */

.intro__grid {
  display: grid;
  grid-template-columns: 1fr 527px;
  gap: 48px;
  align-items: center;
  margin-bottom: 56px;
}

.intro__copy h2 {
  margin-bottom: 20px;
}

.intro__copy p + p {
  margin-top: 14px;
}

.intro__actions {
  margin-top: 28px;
}

.media {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface-2);
}

.media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

.media--tall {
  aspect-ratio: 527 / 475;
}

.media:hover img {
  transform: scale(1.04);
}

/* The dark band of four "what we do" cards. */
.capabilities {
  background: var(--ink);
  border-radius: var(--r-lg);
  padding: 28px;
}

.capabilities__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}

.cap-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 180px;
  padding: 18px;
  border-radius: 0;
  background: var(--white);
  transition:
    transform 0.4s var(--ease),
    box-shadow 0.4s var(--ease);
}

.cap-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -24px rgba(0, 0, 0, 0.4);
}

.cap-card h3 {
  font-size: 20px;
}

.cap-card p {
  flex: 1;
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted);
}

/* --- Audience split -------------------------------------------------------
   Two equal cards, one per audience, so neither has to read the other's
   pitch. Equal weight is deliberate: making either card larger reads as the
   other being a sideline, which is the exact impression this exists to fix. */

.audience__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

.audience__card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 32px;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid transparent;
  transition:
    border-color 0.4s var(--ease),
    transform 0.4s var(--ease);
}

.audience__card:hover {
  border-color: var(--line-strong);
  transform: translateY(-4px);
}

.audience__card h3 {
  font-size: clamp(1.375rem, 1.2rem + 0.7vw, 1.75rem);
}

.audience__card > p {
  color: var(--body);
}

.audience__points {
  display: grid;
  gap: 10px;
  margin-top: 4px;
  margin-bottom: 4px;
}

.audience__points li {
  position: relative;
  padding-left: 28px;
  font-size: 16px;
  line-height: 1.5;
  color: var(--body);
}

/* A tick rather than a bullet: these are reassurances, not a list of parts. */
.audience__points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.36em;
  width: 15px;
  height: 9px;
  border-left: 2px solid var(--navy);
  border-bottom: 2px solid var(--navy);
  transform: rotate(-45deg);
}

.audience__card .btn {
  align-self: flex-start;
  margin-top: 6px;
}

/* --- Project grid --------------------------------------------------------- */

.projects__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}

.project {
  display: block;
}

.project__media {
  position: relative;
  aspect-ratio: 563 / 335;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--surface-2);
  margin-bottom: 16px;
}

.project__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

.project:hover .project__media img {
  transform: scale(1.05);
}

.project__tag {
  position: absolute;
  left: 16px;
  bottom: 16px;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.project__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.project__meta h3 {
  font-size: 22px;
}

.project__year {
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
  flex: none;
}

/* Which audience a job belongs to, in the meta line rather than as a second
   pill on the image — two pills over a photograph starts to look like a
   filter UI that does not filter. */
.project__sector {
  color: var(--brand-text, var(--navy));
}

/* --- About: stats + wide cover + quote ------------------------------------ */

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  max-width: 900px;
  margin: 0 auto 48px;
  text-align: center;
}

.stat__value {
  font-family: var(--display);
  font-size: clamp(2rem, 1.5rem + 2vw, 2.75rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.055em;
  color: var(--ink);
}

.stat__label {
  margin-top: 6px;
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
}

.cover {
  position: relative;
  aspect-ratio: 1150 / 620;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--surface-2);
  margin-bottom: 40px;
}

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

.quote {
  max-width: 780px;
  margin-inline: auto;
  text-align: center;
}

.quote p {
  font-family: var(--display);
  font-size: clamp(1.25rem, 1rem + 1vw, 1.625rem);
  line-height: 1.45;
  letter-spacing: -0.045em;
  color: var(--ink);
}

.quote__by {
  margin-top: 20px;
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
}

.quote__by strong {
  display: block;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

/* --- Services ------------------------------------------------------------- */

.services__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.service {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 28px;
  border-radius: var(--r-lg);
  background: var(--surface);
  transition:
    background-color 0.4s var(--ease),
    transform 0.4s var(--ease);
}

.service:hover {
  background: var(--surface-2);
  transform: translateY(-4px);
}

.service__icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 0;
  background: var(--navy-tint);
  color: var(--navy);
  margin-bottom: 4px;
}

.service__icon svg {
  width: 21px;
  height: 21px;
}

.service p {
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted);
}

/* --- Testimonials --------------------------------------------------------- */

.testimonials__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.testimonial {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 24px;
  border-radius: var(--r-card);
  background: var(--surface);
}

.testimonial p {
  flex: 1;
  font-size: 16px;
  line-height: 1.6;
  color: var(--body);
}

.testimonial__by {
  display: flex;
  align-items: center;
  gap: 12px;
}

.testimonial__avatar {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--navy);
  color: var(--white);
  font-family: var(--display);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.03em;
  flex: none;
}

.testimonial__name {
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.testimonial__role {
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
}

.stars {
  display: flex;
  gap: 3px;
  color: var(--navy);
}

.stars svg {
  width: 15px;
  height: 15px;
}

/* --- FAQ ------------------------------------------------------------------ */

.faq__layout {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: 56px;
  align-items: start;
}

.faq__list {
  border-top: 1px solid var(--line);
}

.faq__item {
  border-bottom: 1px solid var(--line);
}

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  width: 100%;
  padding: 20px 0;
  text-align: left;
  font-family: var(--display);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.faq__sign {
  position: relative;
  width: 20px;
  height: 20px;
  flex: none;
}

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: var(--ink);
  transform: translate(-50%, -50%);
  transition: transform 0.35s var(--ease);
}

.faq__sign::before {
  width: 13px;
  height: 1.5px;
}

.faq__sign::after {
  width: 1.5px;
  height: 13px;
}

.faq__item.is-open .faq__sign::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

/* Animating grid-template-rows from 0fr to 1fr opens the panel to its own
   natural height without measuring it in JS or hard-coding a max-height. */
.faq__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s var(--ease);
}

.faq__item.is-open .faq__a {
  grid-template-rows: 1fr;
}

.faq__a > div {
  overflow: hidden;
}

.faq__a p {
  padding-bottom: 20px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--body);
}

/* --- CTA band ------------------------------------------------------------- */

.cta {
  padding: 0 var(--gutter) var(--section-y);
}

.cta__card {
  position: relative;
  max-width: 1150px;
  margin-inline: auto;
  border-radius: var(--r-xl);
  overflow: hidden;
  padding: 84px 32px;
  text-align: center;
  background: var(--ink);
  isolation: isolate;
}

.cta__card img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cta__card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(12, 16, 24, 0.78);
}

.cta__card h2 {
  color: var(--white);
  max-width: 620px;
  margin: 14px auto 16px;
}

.cta__card p {
  max-width: 520px;
  margin-inline: auto;
  color: rgba(255, 255, 255, 0.82);
}

.cta__buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 30px;
}

/* --- Contact form --------------------------------------------------------- */

.contact__layout {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 56px;
  align-items: start;
}

.contact__cards {
  display: grid;
  gap: 16px;
}

.contact-card {
  display: flex;
  gap: 16px;
  padding: 24px;
  border-radius: var(--r-card);
  background: var(--surface);
}

.contact-card__icon {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 0;
  background: var(--navy-tint);
  color: var(--navy);
  flex: none;
}

.contact-card__icon svg {
  width: 19px;
  height: 19px;
}

.contact-card h3 {
  font-size: 18px;
  margin-bottom: 4px;
}

.contact-card a {
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
  border-bottom: 1px solid var(--line-strong);
}

.contact-card a:hover {
  border-color: var(--navy);
  color: var(--navy);
}

.form {
  display: grid;
  gap: 16px;
  padding: 28px;
  border-radius: var(--r-lg);
  background: var(--surface);
}

.form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.field {
  display: grid;
  gap: 7px;
}

.field label {
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: 0;
  border: 1px solid var(--line);
  background: var(--white);
  font-family: var(--sans);
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
  transition:
    border-color 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

.field textarea {
  min-height: 130px;
  resize: vertical;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--navy);
  box-shadow: 0 0 0 3px var(--navy-tint);
}

.form__note {
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
}

.form__status {
  display: none;
  padding: 12px 14px;
  border-radius: 0;
  background: var(--navy-tint);
  color: var(--navy);
  font-size: 15px;
}

.form__status.is-shown {
  display: block;
}

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

.footer {
  border-top: 1px solid var(--line);
  padding-block: 56px 32px;
}

.footer__top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 40px;
  padding-bottom: 40px;
}

.footer__brand p {
  margin-top: 14px;
  max-width: 280px;
  font-size: 16px;
  color: var(--muted);
}

.footer h4 {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.04em;
  color: var(--muted);
  margin-bottom: 14px;
}

.footer__links {
  display: grid;
  gap: 10px;
}

.footer__links a,
.footer__links li {
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--ink);
}

.footer__links a:hover {
  color: var(--navy);
}

.footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  font-size: 14px;
  letter-spacing: -0.04em;
  color: var(--muted);
}

/* --- Page header (inner pages) -------------------------------------------- */

.page-head {
  padding: 64px 0 48px;
  border-bottom: 1px solid var(--line);
}

.page-head p {
  max-width: 620px;
  margin-top: 16px;
}

/* --- Scroll reveal -------------------------------------------------------- */

/* Elements start shifted and are released by IntersectionObserver. Guarded on
   a `js` class so that with JavaScript off the content is simply visible
   rather than permanently invisible. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.7s var(--ease),
    transform 0.7s var(--ease);
}

.js [data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .js [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .marquee__track {
    animation: none;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

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

@media (max-width: 1024px) {
  .intro__grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .capabilities__grid,
  .services__grid,
  .testimonials__grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .audience__grid {
    gap: 16px;
  }

  .audience__card {
    padding: 26px;
  }

  .faq__layout,
  .contact__layout {
    grid-template-columns: 1fr;
    gap: 36px;
  }

  .footer__top {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 767px) {
  :root {
    --gutter: 18px;
    --section-y: 48px;
  }

  body {
    font-size: 16px;
  }

  /* Below the breakpoint the links collapse into a drawer, so they leave the
     bar entirely rather than wrapping it onto a second line. */
  .nav__links {
    position: fixed;
    inset: 82px 18px auto;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 12px;
    border-radius: var(--r-lg);
    background: var(--white);
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.28);
    border: 1px solid var(--line);
    transform-origin: top;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition:
      opacity 0.25s var(--ease),
      transform 0.25s var(--ease);
  }

  .nav__links.is-open {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .nav__links a {
    padding: 12px 10px;
    border-radius: 0;
    font-size: 17px;
  }

  .nav__links a::after {
    display: none;
  }

  .nav__links a:hover,
  .nav__links a[aria-current="page"] {
    background: var(--surface);
  }

  .nav__toggle {
    display: grid;
  }

  /* The header CTA is the one thing worth keeping visible on a phone, but it
     loses its label so the bar still fits a 360px screen. */
  .nav__actions .btn span.btn__text {
    display: none;
  }

  /* Same balance as the desktop, scaled to 30px a side. The bar's 12px and
     8.5px of slack are unchanged on a phone, so the top padding carries the
     remainder and the bottom pairs with .partners' 12px. */
  .hero {
    padding: 9.5px var(--gutter) 18px;
  }

  .hero__card {
    /* Less is reserved than on a desktop: the bar is the same height but the
       card's own margins are smaller, and a phone has less to spare. */
    min-height: clamp(400px, calc(100vh - 200px), 500px);
    min-height: clamp(400px, calc(100svh - 200px), 500px);
    padding: 20px 20px 28px;
  }

  /* Stacked. The first panel is sized so the second one's top edge is visible
     underneath it — a panel that ends exactly at the fold reads as the whole
     hero, and the second audience is never discovered.

     Once stacked, "outside" means the top of the first and the bottom of the
     last, so the rounding rotates with the layout. Without this the desktop
     rule would leave both panels rounded down their left edge only, which
     reads as a mistake. */
  .hero-split__grid {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .hero-split__grid > .hero-panel:first-child {
    border-radius: var(--r-hero) var(--r-hero) 0 0;
  }

  .hero-split__grid > .hero-panel:last-child {
    border-radius: 0 0 var(--r-hero) var(--r-hero);
  }

  /* Taller on a phone too, but capped tighter than the desktop: these stack,
     so every pixel is paid for twice and the second panel has to stay
     discoverable. At 360px the second one is all but fully visible on a
     812px handset. */
  .hero-panel {
    min-height: clamp(300px, calc(100svh - 420px), 360px);
    padding: 22px 20px;
  }

  /* The diagonal scrim earns its keep on a landscape card, where it can spare
     the right-hand side. A phone's card is portrait and the crop is so tight
     there is no right-hand side left to spare — the diagonal just runs out
     under the headline, which measured 3.7:1. Straight vertical instead:
     headline 4.54:1, pill 7.04:1, and a brighter picture than the diagonal
     managed at this size. */
  .hero__scrim {
    background: linear-gradient(
      to top,
      rgba(12, 16, 24, 0.92) 0%,
      rgba(12, 16, 24, 0.8) 55%,
      rgba(12, 16, 24, 0.4) 88%,
      rgba(12, 16, 24, 0.44) 100%
    );
  }

  .hero__body p {
    font-size: 16px;
  }

  .hero__buttons .btn {
    flex: 1 1 auto;
    justify-content: center;
  }

  .section-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 20px;
    margin-bottom: 32px;
  }

  .capabilities {
    padding: 16px;
  }

  .capabilities__grid,
  .services__grid,
  .testimonials__grid,
  .projects__grid,
  .audience__grid,
  .form__row {
    grid-template-columns: 1fr;
  }

  .audience__card {
    padding: 24px;
  }

  .stats {
    grid-template-columns: repeat(2, 1fr);
    gap: 28px 16px;
  }

  .cta__card {
    padding: 56px 20px;
  }

  .footer__top {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .marquee__track {
    gap: 36px;
  }
}
