/* ============================================================================
   IBB — Page-level compositions
   Built only from the tokens and components; no new colour or spacing values.
   ========================================================================== */

/* ============================== HOME HERO =================================
   The one place on the site where a photograph runs full-bleed behind text.
   The scrim is a real gradient tuned for contrast — not a colour wash
   borrowed from the section above it.
   ========================================================================= */
.hero {
  position: relative;
  display: flex; align-items: center;
  min-height: min(92vh, 900px);
  padding-block: calc(var(--nav-h) + var(--s-8)) var(--s-12);
  background: var(--brand-primary-dark);
  color: var(--text-on-dark);
  overflow: hidden;
  isolation: isolate;
}
.hero__media {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 62%;
}
.hero__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(105deg, rgba(13, 27, 62, .94) 0%, rgba(13, 27, 62, .82) 42%,
                            rgba(13, 27, 62, .5) 72%, rgba(13, 27, 62, .42) 100%),
    linear-gradient(to bottom, rgba(13, 27, 62, .55) 0%, rgba(13, 27, 62, 0) 28%,
                               rgba(13, 27, 62, 0) 76%, rgba(13, 27, 62, .8) 91%,
                               rgba(13, 27, 62, 1) 100%);
}
.hero__inner { max-width: 780px; }
.hero__mark { width: 116px; color: var(--text-on-dark); margin-bottom: var(--s-4); }
.hero h1 { color: #fff; }
/* the "WE ARE…" line, resolved to a static, fully legible state */
.hero__weare {
  display: block; margin-bottom: 6px;
  font-family: var(--font-body); font-weight: 600;
  font-size: clamp(1rem, .9rem + .5vw, 1.25rem);
  letter-spacing: var(--ls-kicker); text-transform: uppercase;
  color: var(--brand-accent);
}
.hero__tagline {
  margin-top: var(--s-4);
  font-size: clamp(.8125rem, .75rem + .3vw, .9375rem);
  font-weight: 600; letter-spacing: .22em; text-transform: uppercase;
  color: var(--text-on-dark-muted);
}
.hero__rule {
  width: 64px; height: 3px; margin: var(--s-4) 0 0; border: 0; border-radius: 2px;
  background: var(--brand-accent);
  transform-origin: left center;
}
.hero .btn-row { margin-top: var(--s-6); }

/* hero entrance — resolves to a static state, never gates readability */
.js .hero__mark, .js .hero__weare, .js .hero h1 .hero__name,
.js .hero__rule, .js .hero__tagline, .js .hero .btn-row {
  opacity: 0; transform: translateY(16px);
  animation: heroIn .8s var(--ease-out) forwards;
}
.js .hero__mark    { animation-delay: .05s; }
.js .hero__weare   { animation-delay: .22s; }
.js .hero h1 .hero__name { animation-delay: .34s; }
.js .hero__rule    { animation-delay: .5s; }
.js .hero__tagline { animation-delay: .58s; }
.js .hero .btn-row { animation-delay: .68s; }
@keyframes heroIn { to { opacity: 1; transform: none; } }

/* the mark itself wipes in, as if the line work were being drawn */
.js .hero__mark { -webkit-mask-composite: source-in; }
.js .hero__mark::after { content: none; }
.js .hero__mark { clip-path: inset(0 100% 0 0); animation: heroIn .8s var(--ease-out) .05s forwards,
                                                            drawIn 1.1s var(--ease-out) .12s forwards; }
@keyframes drawIn { to { clip-path: inset(0 0 0 0); } }

@media (prefers-reduced-motion: reduce) {
  .js .hero__mark, .js .hero__weare, .js .hero h1 .hero__name,
  .js .hero__rule, .js .hero__tagline, .js .hero .btn-row {
    opacity: 1; transform: none; animation: none; clip-path: none;
  }
}

/* ============================== PAGE HERO =================================
   Every page other than home opens on a flat brand-colour block, so the two
   photographic moments on the site stay special.
   ========================================================================= */
.page-hero {
  position: relative;
  --hero-copy: 720px;               /* the text column; the mark lives on what's left */
  padding-block: calc(var(--nav-h) + var(--s-8)) var(--s-8);
  background: var(--brand-primary-dark);
  color: var(--text-on-dark-muted);
  overflow: hidden;
}
.page-hero h1 { color: #fff; max-width: 16ch; }
.page-hero .lede { margin-top: var(--s-3); color: var(--text-on-dark-muted); }
.page-hero__inner { position: relative; z-index: 1; max-width: var(--hero-copy); }
.page-hero::after {                 /* the mark, ghosted, as a quiet brand watermark */
  content: ""; position: absolute; pointer-events: none;
  /* Pinned by its LEFT edge to just past the copy, so it can never run under the
     text however wide the window gets, and then over-sized so it runs off the
     right of the block. The mark is two bears sharing a world map: the cut lands
     about 70% across, which leaves the near bear whole and reads as the far one
     continuing out of frame — cutting later clips the second bear's head, which
     just looks broken. Its own ratio is taller than the strip it sits in, so on
     the shorter heroes it grazes top and bottom too. */
  --mark-left: calc(max(0px, (100% - var(--content)) / 2) + var(--gutter) + var(--hero-copy) + var(--s-6));
  --mark-over: 1.43;                /* 1 / .7 — the share that hangs off the edge */
  left: var(--mark-left);
  top: 52%; transform: translateY(-50%);   /* 2% of the block height below centre */
  width: calc((100% - var(--mark-left)) * var(--mark-over));
  aspect-ratio: var(--bear-ratio);
  background-color: rgba(255, 255, 255, .045);
  -webkit-mask-image: url(../assets/logos/bear.svg); mask-image: url(../assets/logos/bear.svg);
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-position: center; mask-position: center;
}
/* Under this the copy takes the whole shell — no strip is left for the mark. */
@media (max-width: 1023px) { .page-hero::after { content: none; } }

/* ============================== SPLIT ROW ================================= */
.split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(var(--s-4), 4vw, var(--s-12));
  align-items: center;
}
.split--media-first .split__media { order: -1; }
.split__media { position: relative; }
.split__media img {
  position: relative; z-index: 1;
  width: 100%; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
@media (max-width: 899px) {
  .split { grid-template-columns: minmax(0, 1fr); gap: var(--s-6); }
  .split--media-first .split__media { order: 0; }
}

/* ---- heading beside its supporting copy, as two real columns ------------ */
.lead-pair {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(var(--s-4), 5vw, var(--s-12));
  align-items: start;
}
@media (max-width: 899px) { .lead-pair { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); } }

/* ---- a section heading with its call to action pinned opposite ---------- */
.head-row {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s-6); flex-wrap: wrap;
}
.head-row .sec-head { flex: 1 1 480px; }
.head-row__cta { flex: none; }
@media (max-width: 767px) { .head-row { align-items: flex-start; gap: var(--s-4); } }

/* ---- a photograph given the full content width, as it deserves ---------- */
/* ============================ HERO DESCENT ================================
   This band picks the hero's ink navy up at full strength and holds it behind
   both the stats and the group photo, so the skyline resolves into a ground of
   the same tone rather than into white.

   The band ends on a clean edge: flat navy all the way down to the section
   boundary, meeting the white section below with no ramp. The top padding is
   cut to half the standard section rhythm — the hero above is the same navy,
   so the stats can ride high without reading as crowded — while the bottom
   keeps 85% so the photo is not pinched against the white edge.
   ========================================================================= */
.section--descent {
  padding-block: calc(var(--section-y) * .85);
  color: var(--text-on-dark-muted);
  background: var(--brand-primary-dark);
}
/* the photo clears the stats by more than it would in a plain section, so the
   band reads as one dark field rather than two stacked blocks */
.section--descent .feature-photo { margin-top: calc(var(--s-12) * .85); isolation: isolate; }

/* A navy wash over the group photo. Plain alpha rather than multiply: it lifts
   the photo's blacks toward the band's own navy, which is what actually makes
   it sit in the background instead of punching a bright rectangle through it. */
.section--descent .feature-photo img { filter: saturate(.82); }
.section--descent .feature-photo::before {
  content: ""; position: absolute; inset: 0; z-index: 2;
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, rgba(13, 27, 62, .36), rgba(13, 27, 62, .26));
  pointer-events: none;
}

.feature-photo {
  position: relative;
  margin: var(--s-8) 0 0;
}
.feature-photo img {
  position: relative; z-index: 1;
  width: 100%; border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.feature-photo::after {             /* offset gold rule — a small piece of craft */
  content: ""; position: absolute; left: -16px; bottom: -16px;
  width: 34%; height: 62%; z-index: 0;
  border-left: 3px solid var(--brand-accent);
  border-bottom: 3px solid var(--brand-accent);
  border-radius: 0 0 0 var(--radius-lg);
}
@media (max-width: 767px) {
  .feature-photo { margin-top: var(--s-6); }
  .feature-photo::after { left: -8px; bottom: -8px; }
}

/* =========================== RECRUITMENT BAND =============================
   The join page's timeline band runs tighter than the standard section rhythm
   so the five stages read as one compact block, and gives the timeline a
   companion column: a reserved frame that the recruitment graphic will fill.

   The grid mirrors .lead-pair's columns and gap exactly, so the frame's column
   lands directly beneath the lede paragraph above it and the two share a
   centreline. Three things are being aligned here, and the row structure is
   what makes each of them exact rather than eyeballed:

   1. .recruit-grid__main is display:contents, so the timeline and the frame's
      cell are siblings in the SAME grid row. The cell stretches to that row —
      i.e. to the timeline's height — and the frame floats centred inside it,
      out of flow, so the two centrelines coincide exactly. The frame is now the
      taller of the two and overhangs the row by ~25px top and bottom; keeping
      it out of flow means that overhang cannot push the button down and undo
      the spacing in point 3.
   2. Column 1 is max-content, i.e. exactly as wide as the timeline's longest
      line (~324px) rather than the half-column the stages used to be stretched
      across. The apply button sits in row 2 of that column and is centred
      across it, which puts it on the timeline's true optical centre — centring
      it on the half-column left it ~108px too far right, floating in the empty
      space past the ends of the stage text.

      Column 1 no longer matching .lead-pair's half-column is why the frame's
      cell spans the whole grid and places the frame at 75% + gap/4 instead: on
      a two-column grid of any width that expression IS the centre of the
      second half-column, so the frame stays on the lede's centreline above it
      no matter what column 1 does.
   3. The band's bottom padding is carried by the button row itself
      (--recruit-y above it, the same below it) instead of by the section, so
      the button sits exactly midway between the timeline and the end of the
      blue. row-gap is zeroed for the same reason — the grid gap is a column
      gap only, or it would add itself to the space above the button.

   Below 900px the frame drops away rather than stacking as a large empty box
   under the timeline.
   ========================================================================= */
.section--recruit {
  --recruit-y: calc(var(--section-y) * .72);
  padding-block: var(--recruit-y) 0;
}

.recruit-grid {
  --recruit-gap: clamp(var(--s-4), 5vw, var(--s-12));
  margin-top: var(--s-8);
  display: grid; align-items: center;
  grid-template-columns: minmax(0, max-content) minmax(0, 1fr);
  column-gap: var(--recruit-gap);
  row-gap: 0;
}
.recruit-grid__main { display: contents; }
.recruit-grid .timeline { grid-area: 1 / 1; }
.recruit-grid .recruit-frame-cell {
  position: relative; pointer-events: none;
  grid-column: 1 / -1; grid-row: 1;
  align-self: stretch;
}
.recruit-grid__main .btn-row {
  grid-area: 2 / 1;
  justify-content: center;
  margin-top: var(--recruit-y);
  padding-bottom: var(--recruit-y);
}

.recruit-frame {
  position: absolute;
  top: 50%; left: calc(75% + var(--recruit-gap) / 4);
  transform: translate(-50%, -50%);
  height: clamp(384px, 41vw, 624px);
  aspect-ratio: 4 / 5;
  border: 1.5px dashed rgba(255, 255, 255, .28);
  border-radius: var(--radius-lg);
  background: rgba(13, 27, 62, .22);
}
@media (max-width: 899px) {
  .recruit-grid { grid-template-columns: minmax(0, max-content); column-gap: 0; }
  .recruit-grid .recruit-frame-cell { display: none; }
}

/* ============================== CTA BAND ==================================
   Two columns, so the copy never floats alone in an oversized dark void.
   ========================================================================= */
.cta-band {
  display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(var(--s-4), 5vw, var(--s-12));
  align-items: center;
}
@media (max-width: 899px) { .cta-band { grid-template-columns: minmax(0, 1fr); gap: var(--s-6); } }

/* two audience paths, side by side */
.paths { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
@media (max-width: 599px) { .paths { grid-template-columns: minmax(0, 1fr); } }
.path {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-4);
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--border-subtle-dark);
  border-radius: var(--radius-lg);
  text-decoration: none; color: var(--text-on-dark-muted);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.path:hover {
  background: rgba(255, 255, 255, .1); border-color: rgba(255, 255, 255, .3);
  transform: translateY(-4px); color: var(--text-on-dark-muted);
}
.path__title {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-2);
  color: #fff; font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.125rem, 1rem + .45vw, 1.375rem);
}
.path__title span { white-space: nowrap; }
.path__title svg { width: 20px; height: 20px; color: var(--brand-accent); flex: none;
                   transition: transform var(--dur) var(--ease); }
.path:hover .path__title svg { transform: translateX(4px); }
.path__body { font-size: var(--fs-sm); }
/* light variant, on the contact page */
.paths--light .path { background: var(--surface-white); border-color: var(--border-subtle);
                      color: var(--text-body); box-shadow: var(--shadow-sm); }
.paths--light .path:hover { background: var(--surface-white); box-shadow: var(--shadow-md);
                            border-color: rgba(13, 27, 62, .2); }
.paths--light .path__title { color: var(--text-primary); }

/* ============================== TEAM ======================================
   One card component for every member; the grid is what changes per tier.
   ========================================================================= */
.team-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-6) var(--s-4); }
.team-grid { justify-items: stretch; }
.team-grid > .member { width: 100%; }

/* The board sits three up, and twelve divides evenly by three (and by two, and by
   one) — so every row of the board is full at every breakpoint. Its frames run
   20% smaller on both axes; the 4/5 ratio ties height to width, so width does it. */
.team-grid--board .member__frame { width: 80%; }

/* Consultants wrap as flex rather than grid. A hand-maintained roster seldom
   divides evenly into the column count, so the row that ends the list is usually
   short. Flex centres that trailing row instead of leaving a run of empty cells
   hanging off the right — whatever the count happens to be, which is why this
   note names none. Column counts are unchanged; the widths below restate them. */
.team-grid--members { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--s-3); }
.team-grid--members > .member { width: calc((100% - var(--s-3) * 5) / 6); }

@media (max-width: 1199px) {
  .team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .team-grid--members > .member { width: calc((100% - var(--s-3) * 2) / 3); }
}
@media (max-width: 767px) {
  .team-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-3); }
  .team-grid--members > .member { width: calc((100% - var(--s-3)) / 2); }
}
@media (max-width: 479px) {
  .team-grid { grid-template-columns: minmax(0, 1fr); }
  .team-grid--members > .member { width: 100%; }
}

.member { display: flex; flex-direction: column; }
.member__frame {
  position: relative;
  aspect-ratio: 4 / 5;                /* every headshot is cropped to the same frame */
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--brand-primary);
  box-shadow: var(--shadow-sm);
}
.member__frame > img {          /* the portrait; the badge img is nested deeper */
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--dur-slow) var(--ease), filter var(--dur-slow) var(--ease);
}
.member__frame::after {               /* soft navy duotone, evens out mixed lighting */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(13, 27, 62, .34), rgba(13, 27, 62, .04) 55%);
  mix-blend-mode: multiply;
  opacity: .55;
  transition: opacity var(--dur-slow) var(--ease);
}
.member:hover .member__frame > img { transform: scale(1.045); }

/* monogram, for members with no photograph on the current site */
.member__frame--empty {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, var(--brand-primary) 0%, var(--brand-primary-dark) 100%);
}
.member__initials {
  font-family: var(--font-display); font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem);
  font-weight: 600; letter-spacing: .02em; color: rgba(255, 255, 255, .82);
}
.member__frame--empty::after { content: none; }

.member__name {
  margin-top: var(--s-2);
  font-family: var(--font-body); font-size: 1.0625rem; font-weight: 600;
  color: var(--text-primary); line-height: 1.35;
}
.member__role { margin-top: 2px; font-size: var(--fs-sm); color: var(--brand-primary-mid); font-weight: 500; }
.member__where {
  margin-top: 4px; font-size: var(--fs-xs); color: var(--text-muted);
  display: flex; align-items: center; gap: 6px;
}
.member__where svg { width: 13px; height: 13px; flex: none; opacity: .7; }

/* ---- hover a card: the portrait drops to black and white behind a scrim, and
   a LinkedIn chip rises in the middle. The whole frame is the click target —
   the chip names the action rather than being the only thing you can hit. The
   z-index matters: .member__frame::after is a pseudo-element, so it paints
   after every child and would otherwise sit on top of the link. */
.member__link {
  position: absolute; inset: 0; z-index: 1;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, .55);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.member__badge {                /* the official mark — already a circle, so no chip */
  /* One knob: the ring and the gap are struck off --badge so the whole button
     scales in proportion. border-box, so at 56px the mark lands at 46px inside
     a 3px gap and a 2px ring — the gap is what makes the ring read as a button
     edge rather than as part of the logo. */
  --badge: 56px;
  width: var(--badge); height: var(--badge);
  padding: calc(var(--badge) * 3 / 56);
  border: calc(var(--badge) * 2 / 56) solid rgba(255, 255, 255, .95);
  border-radius: 50%;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .5);
  transform: scale(.86);
  transition: transform var(--dur) var(--ease);
}
/* Consultant cards run six to a row against the board's three, so the button
   that suits a board portrait sits too heavy on them. */
.team-grid--members .member__badge { --badge: 42px; }
/* Greyscale is scoped to the portrait, and the scrim is neutral black rather than
   the brand navy, so the whole card reads monochrome and the blue of the mark is
   the only colour left. The duotone goes to zero for the same reason. */
.member:hover .member__frame > img { filter: grayscale(1); }
.member:hover .member__frame::after { opacity: 0; }
.member:hover .member__link,
.member__link:focus-visible { opacity: 1; }
.member:hover .member__badge,
.member__link:focus-visible .member__badge { transform: scale(1); }
.member__link:focus-visible { outline: 3px solid var(--brand-accent); outline-offset: -3px; }

/* Keyboard users get the same reveal on focus; pointer users on hover. */
@media (prefers-reduced-motion: reduce) {
  .member__badge, .member:hover .member__badge,
  .member__link:focus-visible .member__badge { transform: none; }
}

.member[hidden] { display: none; }


/* ============================== MISC ====================================== */
.rule-list { border-top: 1px solid var(--border-subtle); }
.rule-list li {
  display: flex; gap: var(--s-2); align-items: flex-start;
  padding: var(--s-2) 0; border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm);
}
.rule-list svg { width: 18px; height: 18px; flex: none; margin-top: 3px; color: var(--brand-accent); }

.contact-grid {
  display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(var(--s-4), 5vw, var(--s-12));
  align-items: start;
}
.contact-grid > * { align-self: start; }
.contact-grid .card { height: auto; }
@media (max-width: 899px) { .contact-grid { grid-template-columns: minmax(0, 1fr); gap: var(--s-6); } }

.info-row { display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); }
.info-row + .info-row { margin-top: var(--s-2); }
.info-row svg { width: 18px; height: 18px; color: var(--brand-accent); flex: none; }
