/* ==========================================================================
   Net-Vendor - navigation, hero, and page sections
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Navigation - floating pill, inverts once past the hero
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  top: var(--s-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-nav);
  width: calc(100% - (var(--gutter) * 2));
  /* Deliberately narrower than the content shell: a pill that runs the full
     84rem reads as a bar, not as a floating control. */
  max-width: 68rem;
  transition: transform var(--dur-3) var(--ease-out),
              opacity var(--dur-3) var(--ease-out);
}

.nav.is-hidden {
  transform: translateX(-50%) translateY(calc(-100% - var(--s-6)));
  opacity: 0;
}

.nav__inner {
  /* Three tracks rather than space-between, so the links sit on the centre of
     the pill instead of wherever the brand and the actions leave them. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
  padding: 0.5rem 0.5rem 0.5rem 1.25rem;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(18px) saturate(1.6);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  transition: background-color var(--dur-3) var(--ease-out),
              border-color var(--dur-3) var(--ease-out),
              color var(--dur-3) var(--ease-out);
}

/* Over the black hero the pill goes dark-glass */
.nav[data-on-dark="true"] .nav__inner {
  background: rgba(19, 21, 25, 0.62);
  border-color: rgba(255, 255, 255, 0.14);
  color: #fff;
}

.nav__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.03em;
  flex: none;
}

.nav__mark {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--nv-blue);
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: -0.04em;
  flex: none;
}

.nav__links {
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  grid-column: 2;
}

@media (min-width: 62rem) {
  .nav__links { display: flex; }
}

.nav__link {
  position: relative;
  padding: 0.5rem 0.8rem;
  border-radius: var(--r-pill);
  font-size: var(--t-sm);
  font-weight: 500;
  color: inherit;
  opacity: 0.72;
  transition: opacity var(--dur-2) var(--ease-out),
              background-color var(--dur-2) var(--ease-out);
}
.nav__link:hover,
.nav__link[aria-current="page"] {
  opacity: 1;
  background: rgba(10, 11, 13, 0.06);
}
.nav[data-on-dark="true"] .nav__link:hover,
.nav[data-on-dark="true"] .nav__link[aria-current="page"] {
  background: rgba(255, 255, 255, 0.12);
}

.nav__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-2);
  grid-column: 3;
  min-width: 0;
}

/* Below the tablet breakpoint the pill carries brand + burger only.
   The CTA is repeated at the top of the drawer, so nothing is lost. */
.nav__actions .btn { display: none; }

@media (min-width: 30rem) {
  .nav__actions .btn { display: inline-flex; }
}

/* Mobile menu */
.nav__burger {
  /* Flex column with a real gap: as an auto-row grid the three bars were
     spread across the full 40px button instead of sitting as one mark. */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: inherit;
  cursor: pointer;
}
@media (min-width: 62rem) { .nav__burger { display: none; } }

.nav__burger span {
  display: block;
  width: 17px;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur-3) var(--ease-out),
              opacity var(--dur-2) var(--ease-out);
}
.nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.nav__drawer {
  position: absolute;
  top: calc(100% + var(--s-2));
  left: 0;
  right: 0;
  padding: var(--s-5);
  border-radius: var(--r-xl);
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  box-shadow: var(--shadow-lg);
  display: grid;
  gap: var(--s-1);
  transform-origin: top center;
  transform: translateY(-10px) scale(0.98);
  opacity: 0;
  visibility: hidden;
  transition: transform var(--dur-3) var(--ease-out),
              opacity var(--dur-3) var(--ease-out),
              visibility 0s linear var(--dur-3);
}
.nav__drawer.is-open {
  transform: translateY(0) scale(1);
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}
@media (min-width: 62rem) { .nav__drawer { display: none; } }

.nav__drawer a {
  padding: 0.75rem 0.5rem;
  border-radius: var(--r-sm);
  font-size: 1.0625rem;
  font-weight: 500;
  color: var(--nv-black);
  border-bottom: 1px solid var(--rule);
}
.nav__drawer a.btn,
.nav__drawer a.meta { border-bottom: 0; }

/* The drawer sets its own link colour, which outranks .btn and left the blue
   CTA with black type on it. Hand the button its own colour back. */
.nav__drawer a.btn { color: var(--btn-fg); }
.nav__drawer a.meta { color: var(--fg-muted); font-size: var(--t-label); }

/* --------------------------------------------------------------------------
   2. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: min(100svh, 62rem);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background: var(--nv-black);
  color: #fff;
  overflow: hidden;
  padding-top: 7rem;
}

/* Real photography sits under the gradient. Desaturated and dimmed so it reads
   as texture and depth rather than a picture competing with the headline. */
.hero__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
}
.hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 38%;
  filter: grayscale(0.92) contrast(1.2) brightness(0.28);
  transform: scale(1.06);
}

.hero__canvas {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  opacity: 0;
  /* screen: the canvas paints black everywhere except the blooms, and black
     is a no-op under screen - so the photo shows through and only the blue
     light lands on top of it. */
  mix-blend-mode: screen;
  transition: opacity 1.2s var(--ease-out);
}
/* A second brake on the wash, independent of the bloom alphas. */
.hero__canvas.is-ready { opacity: 0.72; }

.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(10, 11, 13, 0.78) 0%, transparent 36%),
    linear-gradient(0deg, rgba(10, 11, 13, 0.92) 0%, rgba(10, 11, 13, 0.35) 46%, transparent 68%);
}

.hero__grain {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0.22;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
}

.hero__inner {
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-bottom: var(--s-6);
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
}

.hero__top {
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 62rem) {
  .hero__top {
    grid-template-columns: minmax(0, 1fr) minmax(0, 25rem);
    align-items: end;
    gap: var(--s-8);
  }
}

.hero__eyebrow { color: var(--nv-blue-bright); }
.hero__eyebrow::before { background: currentColor; }

.hero__title {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: 700;
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-hero);
  margin-block: var(--s-4) 0;
}

/* Each line of the headline is its own .line-clip, so the breaks are authored,
   not incidental. nowrap stops the type re-wrapping and orphaning a word when
   the copy column narrows. The scale is capped so this can never overflow. */
.hero__title .line-clip > span { white-space: nowrap; }

/* Inner pages run the same hero. Their headlines carry more words than the
   home one, so the cap comes down a step - everything else is identical. */
.hero--page .hero__title { font-size: clamp(2.25rem, 4.8vw, 4.25rem); }

.hero__title em {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.015em;
  /* Sits on a blue bloom, so tint rather than recolour - keeps contrast. */
  color: #fff;
  padding-right: 0.06em;
}

.hero__sub {
  /* Sits beside a very large headline, so it stays a support line rather than
     a second headline competing with it. */
  font-size: clamp(0.9375rem, 1.05vw, 1.0625rem);
  line-height: 1.55;
  color: var(--fg-on-dark-mut);
  max-width: 34ch;
  text-wrap: pretty;
}

/* Both CTAs sit on one line. That only works because the second label was cut
   to two words and the copy column was widened to match - a long label here
   forces a stack, and a stacked pair of unequal pills reads as broken. */
.hero__cta {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--s-2);
  margin-top: var(--s-4);
}

.hero__cta .btn {
  flex: 0 0 auto;
  justify-content: center;
  white-space: nowrap;
  font-size: var(--t-xs);
  padding: 0.75rem 1.125rem;
}

/* Below the split point the hero is one column, so it goes full width - and
   carries one button, not two, so the block stays short enough to sit low on
   the photograph instead of covering the faces in it. The second CTA is in
   the strip and the drawer, so nothing is lost. */
@media (max-width: 34rem) {
  .hero__cta { flex-wrap: wrap; margin-top: var(--s-3); }
  .hero__cta .btn {
    flex: 1 1 100%;
    font-size: var(--t-xs);
    padding-block: 0.6875rem;
  }
  .hero__cta .btn--ghost-on-dark { display: none; }

  /* The card is a desktop flourish; on a phone it eats a third of the hero. */
  .hero__meta .person-card { display: none; }

  .hero__inner { gap: var(--s-5); padding-bottom: var(--s-4); }
  .hero__sub { font-size: var(--t-sm); }
  .hero__meta { padding-top: var(--s-3); }

  /* Two rows of mono labels over the photograph, repeating links the drawer
     already carries. On a phone they only crowd the picture. The .hero
     qualifier is needed: the base rule is declared further down the sheet. */
  .hero .hero__strip { display: none; }
}

/* Both hero buttons sit on photography, so they need their own ground to stay
   legible no matter what is behind them. */
.hero__cta .btn--ghost-on-dark {
  background: rgba(10, 11, 13, 0.42);
  border-color: rgba(255, 255, 255, 0.28);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.hero__cta .btn--ghost-on-dark:hover {
  background: #fff;
  border-color: #fff;
}

/* Category strip under the hero copy */
.hero__strip {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--rule-on-dark);
}

@media (min-width: 48rem) {
  .hero__strip { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.hero__strip a {
  position: relative;
  padding: var(--s-4) 0;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--fg-on-dark-mut);
  border-bottom: 1px solid var(--rule-on-dark);
  overflow: hidden;
  transition: color var(--dur-2) var(--ease-out);
}
@media (min-width: 48rem) {
  .hero__strip a { border-bottom: 0; }
}
.hero__strip a::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  height: 2px;
  width: 100%;
  background: var(--nv-blue);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out);
}
.hero__strip a:hover { color: #fff; }
.hero__strip a:hover::before { transform: scaleX(1); }

/* Corner meta rail pinned to the very bottom of the hero */
.hero__meta {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--s-4);
  padding-top: var(--s-5);
}

.hero__meta .person-card { justify-self: end; }
.hero__meta > :last-child { display: none; }

@media (min-width: 62rem) {
  .hero__meta {
    grid-template-columns: 1fr auto 1fr;
  }
  .hero__meta .person-card { justify-self: center; }
  .hero__meta > :last-child { display: block; justify-self: end; }
}

.hero__scroll {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}
.hero__scroll svg { animation: nudge 2.4s var(--ease-in-out) infinite; }

@keyframes nudge {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50%      { transform: translateY(4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__scroll svg { animation: none; }
}

/* "Meet the CEO" floating card (Mark Studio pattern) */
.person-card {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  padding: 0.5rem 1rem 0.5rem 0.5rem;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.94);
  color: var(--nv-black);
  box-shadow: var(--shadow-lg);
  transition: transform var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.person-card:hover { transform: translateY(-3px); }

.person-card__ph {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 42%;
  flex: none;
}

.person-card__txt { display: grid; line-height: 1.3; }
.person-card__txt b { font-size: var(--t-sm); font-weight: 600; }
.person-card__txt span {
  font-size: var(--t-xs);
  color: var(--fg-muted);
}

/* --------------------------------------------------------------------------
   3. Trust strip / marquee
   -------------------------------------------------------------------------- */

.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee__track {
  display: flex;
  width: max-content;
  gap: clamp(2.5rem, 6vw, 5rem);
  animation: marquee 32s linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }

@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .marquee { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
}

.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--fg-muted);
  white-space: nowrap;
  opacity: 0.72;
  transition: opacity var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.marquee__item:hover { opacity: 1; color: var(--nv-black); }

/* The mark carries the same weight as the word, so it sits on the cap height
   rather than floating beside it, and picks up blue only on hover. */
.marquee__ico {
  width: 1.15em;
  height: 1.15em;
  flex: none;
  color: var(--fg-faint);
  transition: color var(--dur-2) var(--ease-out);
}
.marquee__item:hover .marquee__ico { color: var(--nv-blue); }

@media (prefers-reduced-motion: reduce) {
  .marquee__ico { transition: none; }
}

/* --------------------------------------------------------------------------
   4. Editorial statement block
   -------------------------------------------------------------------------- */

.statement {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3.1vw, 2.625rem);
  font-weight: 500;
  line-height: 1.22;
  letter-spacing: -0.028em;
  text-wrap: balance;
  max-width: 26ch;
}

.statement .hl { color: var(--nv-blue); }

.statement--wide { max-width: 34ch; }

/* Word-by-word reveal used on the big statement */
.w {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.4em);
  transition: opacity 520ms var(--ease-out), transform 520ms var(--ease-out);
}
.is-in .w { opacity: 1; transform: translateY(0); }
.no-js .w { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   4b. Figure - a photograph with a labelled caption rail
   -------------------------------------------------------------------------- */

.figure {
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--nv-black);
  position: relative;
}

.figure picture { display: block; }
.figure img {
  width: 100%;
  height: auto;
  display: block;
  transition: transform var(--dur-5) var(--ease-out),
              filter var(--dur-3) var(--ease-out);
}
.figure:hover img { transform: scale(1.025); }

.figure__cap {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding: var(--s-3) var(--s-4);
  background: var(--nv-black);
  color: var(--fg-on-dark-mut);
  font-size: var(--t-sm);
}
.figure__cap .meta { color: var(--nv-blue-bright); }

/* Same treatment, but the picture is a wide letterbox strip */
.figure--wide img { aspect-ratio: 1600 / 314; object-fit: cover; }

/* --------------------------------------------------------------------------
   5. Stats
   -------------------------------------------------------------------------- */

.stats {
  --stat-pad: clamp(1rem, 2.4vw, 2rem);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem) 0;
}
@media (min-width: 62rem) {
  .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; }
}

.stat {
  position: relative;
  padding-inline: var(--stat-pad);
  padding-block: clamp(0.75rem, 1.6vw, 1.25rem);
  border-radius: var(--r-sm);
}

/* Below the four-up breakpoint the gutter is too narrow to pull the grid out
   of, so the first cell of each row simply sits flush with the shell edge. */
.stats > .stat:nth-child(2n + 1) { padding-left: 0; }

/* One hairline between columns, nothing around the group. */
.stat + .stat::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.15em;
  bottom: 0.15em;
  width: 1px;
  background: var(--rule);
}
.stats > .stat:nth-child(2n + 1)::before { display: none; }

@media (min-width: 62rem) {
  /* The grid is pulled left by one cell's padding, so the first number still
     lines up with the shell edge while every cell keeps the same inset. That
     is what lets the hover card breathe on the first stat as much as the rest. */
  .stats { margin-left: calc(var(--stat-pad) * -1); }
  .stats > .stat:nth-child(2n + 1) { padding-left: var(--stat-pad); }
  .stats > .stat:nth-child(2n + 1)::before { display: block; }
  .stats > .stat:first-child::before { display: none; }
}
.section--dark .stat + .stat::before { background: var(--rule-on-dark); }

.stat__num {
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.4vw, 2.875rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1;
  display: flex;
  align-items: baseline;
  gap: 0.02em;
}
.stat__num .suffix { color: var(--nv-blue); }
.section--dark .stat__num .suffix { color: var(--nv-blue-bright); }

.stat__label {
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--fg-muted);
  line-height: 1.45;
  max-width: 24ch;
  text-wrap: pretty;
}
.section--dark .stat__label { color: var(--fg-on-dark-mut); }

/* Footnote sits on the same hairline that closes the group. */
.stats-note {
  margin-top: clamp(1.25rem, 2.6vw, 2rem);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs, var(--t-sm));
  color: var(--fg-muted);
}
.section--dark .stats-note {
  border-top-color: var(--rule-on-dark);
  color: var(--fg-on-dark-mut);
}

/* --------------------------------------------------------------------------
   6. Numbered service rows (Mark Studio pattern)
   -------------------------------------------------------------------------- */

/* The list closes on a rule so the last row does not bleed into the section. */
.srv-list { border-bottom: 1px solid var(--rule-on-dark); }

.srv {
  display: grid;
  gap: var(--s-3);
  padding-block: clamp(1.5rem, 2.6vw, 2.25rem);
  border-top: 1px solid var(--rule-on-dark);
  align-items: start;
}

@media (min-width: 62rem) {
  .srv {
    /* start, not center: the index number belongs on the title's line, not
       floating halfway down a three-line description. */
    grid-template-columns: 3.5rem minmax(0, 1fr) minmax(0, 16rem);
    gap: var(--s-6);
    align-items: start;
  }
}

.srv__no {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.12em;
  color: var(--fg-on-dark-mut);
  /* optical nudge: drops the number's cap height onto the title's cap height,
     tracking the title's own clamp() so it holds at every width. */
  padding-top: clamp(0.17rem, 0.3vw, 0.3rem);
  transition: color var(--dur-2) var(--ease-out);
}

.srv__title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.4vw, 2.125rem);
  font-weight: 600;
  letter-spacing: -0.028em;
  line-height: 1.12;
  transition: color var(--dur-2) var(--ease-out);
}

.srv__desc {
  margin-top: var(--s-3);
  color: var(--fg-on-dark-mut);
  max-width: 44ch;
  font-size: var(--t-sm);
  line-height: 1.6;
}

.srv .chip-row { margin-top: var(--s-4); }

/* The hovered row owns its number. */
.srv:hover .srv__no,
.srv:focus-within .srv__no { color: var(--nv-blue-bright); }

.srv__media {
  align-self: center;
  border-radius: var(--r-md);
  overflow: hidden;
  transform: scale(0.98);
  transition: transform var(--dur-3) var(--ease-out);
}

.srv__media { aspect-ratio: 16 / 10; }
.srv__media picture { display: contents; }
.srv__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.4) contrast(1.05);
  transition: filter var(--dur-3) var(--ease-out);
}
.srv:hover .srv__media img { filter: grayscale(0) contrast(1.05); }

.srv:hover .srv__title { color: var(--nv-blue-bright); }
.srv:hover .srv__media { transform: scale(1); }

/* --------------------------------------------------------------------------
   7. Deduction code resource block
   -------------------------------------------------------------------------- */

.codes {
  background:
    radial-gradient(80% 110% at 8% 0%, rgba(26, 109, 255, 0.07), transparent 58%),
    var(--nv-paper);
  color: var(--fg);
}

.codes__search {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  max-width: 34rem;
  padding: 0.75rem 0.75rem 0.75rem 1.125rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-pill);
  background: var(--nv-paper);
  transition: border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.codes__search:focus-within {
  border-color: var(--nv-blue);
  box-shadow: 0 0 0 4px rgba(26, 109, 255, 0.12);
}

.codes__search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--fg);
  font-size: var(--t-body);
  outline: none;
}
.codes__search input::placeholder { color: var(--fg-faint); }

.codes__count {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  color: var(--fg-faint);
  white-space: nowrap;
  padding-right: var(--s-2);
}

.codes__table-wrap {
  margin-top: var(--s-6);
  border: 1px solid var(--rule);
  background: var(--nv-paper);
  border-radius: var(--r-lg);
  /* clip, not hidden: clips the corners without adding a second scrollport
     around the one .codes__scroll already owns. */
  overflow: clip;
}

/* The homepage shows a scrollable preview; the full reference lives on
   deduction-codes.html. Without the cap all 89 rows land on the homepage and
   the page triples in length. */
.codes__scroll {
  position: relative;
  max-height: 27rem;
  overflow: auto;
  overscroll-behavior: contain;
}

.codes__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-sm);
}

.codes__table thead th {
  position: sticky;
  /* 0, not a nav offset: the table scrolls inside .codes__scroll, not with the
     page, so the head pins to that box's top edge. */
  top: 0;
  z-index: 2;
  background: var(--nv-paper-2);
  padding: 0.75rem 1rem;
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--fg-muted);
  font-weight: 500;
  /* inset shadow, not border-bottom: with border-collapse a collapsed cell
     border does not travel with the sticky head, so rows scroll past an
     unruled edge. */
  box-shadow: inset 0 -1px 0 var(--rule);
}

.codes__table td {
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.codes__table tbody tr:last-child td { border-bottom: 0; }

.codes__table tbody tr {
  transition: background-color var(--dur-1) var(--ease-out);
}
.codes__table tbody tr:hover { background: var(--nv-blue-tint); }

.codes__paper,
.codes__edi {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.codes__paper { color: var(--nv-blue); font-weight: 600; }
.codes__edi { color: var(--fg-muted); }

.codes__table mark {
  background: rgba(26, 109, 255, 0.20);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}

.codes__empty {
  padding: var(--s-7);
  text-align: center;
  color: var(--fg-muted);
  font-size: var(--t-sm);
}

/* --------------------------------------------------------------------------
   8. Cards
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(1.25rem, 2.4vw, 1.75rem);
  background: var(--nv-paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  transition: transform var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out),
              border-color var(--dur-2) var(--ease-out);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: rgba(26, 109, 255, 0.35);
}

.card__icon {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  background: var(--nv-blue-tint);
  color: var(--nv-blue);
  flex: none;
}

.card__title {
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.card__body {
  font-size: var(--t-sm);
  color: var(--fg-muted);
  line-height: 1.6;
}

.card-grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

/* Feature card with media on top */
.fcard { padding: 0; overflow: hidden; }
.fcard__media { border-radius: 0; }
.fcard__body { padding: clamp(1.25rem, 2.4vw, 1.75rem); display: grid; gap: var(--s-3); }

/* --------------------------------------------------------------------------
   9. Team
   -------------------------------------------------------------------------- */

.team-grid {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
}

/* 4:3, not a portrait crop - the source photographs are landscape and cropping
   them to a tall card would cut people's heads off. */
.member__media {
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--nv-black);
  aspect-ratio: 4 / 3;
}
.member__media picture { display: contents; }
.member__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.5) contrast(1.06);
  transition: transform var(--dur-4) var(--ease-out),
              filter var(--dur-3) var(--ease-out);
}
.member:hover .member__media img {
  transform: scale(1.04);
  filter: grayscale(0) contrast(1.06);
}

.member__name {
  margin-top: var(--s-4);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.member__role {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nv-blue);
  margin-top: 2px;
}
/* Team members without a card yet (no photo or bio). */
.team-more {
  margin-top: var(--s-5);
  font-size: var(--t-sm);
  color: var(--fg-muted);
}

.member__bio {
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--fg-muted);
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   10. Accordion
   -------------------------------------------------------------------------- */

.acc { border-top: 1px solid var(--rule); }

.acc__item { border-bottom: 1px solid var(--rule); }

.acc__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: clamp(1.1rem, 2.2vw, 1.5rem) 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: clamp(1.0625rem, 1.7vw, 1.25rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--fg);
  transition: color var(--dur-2) var(--ease-out);
}
.acc__btn:hover { color: var(--nv-blue); }

.acc__sign {
  position: relative;
  width: 20px;
  height: 20px;
  flex: none;
}
.acc__sign::before,
.acc__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform var(--dur-3) var(--ease-out);
}
.acc__sign::after { transform: rotate(90deg); }
.acc__btn[aria-expanded="true"] .acc__sign::after { transform: rotate(0deg); }

.acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-3) var(--ease-out);
}
.acc__panel.is-open { grid-template-rows: 1fr; }

.acc__panel > div { overflow: hidden; }

.acc__content {
  padding-bottom: clamp(1.1rem, 2.2vw, 1.5rem);
  color: var(--fg-muted);
  max-width: 62ch;
  font-size: var(--t-sm);
  line-height: 1.7;
  display: grid;
  gap: var(--s-3);
}

/* --------------------------------------------------------------------------
   11. CTA band
   -------------------------------------------------------------------------- */

.cta {
  position: relative;
  overflow: hidden;
  background: var(--nv-blue);
  color: #fff;
  border-radius: var(--r-xl);
  padding: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 5vw, 4rem);
  isolation: isolate;
}

.cta::before {
  content: "";
  position: absolute;
  inset: -30%;
  z-index: -1;
  background:
    radial-gradient(45% 55% at 20% 20%, rgba(255, 255, 255, 0.3), transparent 60%),
    radial-gradient(40% 50% at 82% 78%, rgba(10, 11, 13, 0.4), transparent 62%);
  animation: drift 22s var(--ease-in-out) infinite alternate;
}

@keyframes drift {
  from { transform: translate3d(-3%, -2%, 0) scale(1); }
  to   { transform: translate3d(3%, 4%, 0) scale(1.1); }
}
@media (prefers-reduced-motion: reduce) {
  .cta::before { animation: none; }
}

.cta__title {
  font-family: var(--font-display);
  font-size: var(--t-d1);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
  max-width: none;
  text-wrap: balance;
}

.cta__sub {
  margin-top: var(--s-4);
  font-size: var(--t-lead);
  color: rgba(255, 255, 255, 0.78);
  max-width: 46ch;
}

.cta__actions {
  margin-top: var(--s-6);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

/* One column on a phone, so the pair runs full width rather than stacking as
   two pills of different lengths. */
@media (max-width: 34rem) {
  .cta__actions { gap: var(--s-2); }
  .cta__actions .btn { flex: 1 1 100%; justify-content: center; }
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */

.footer {
  background: var(--nv-black);
  color: #fff;
  padding-block: clamp(3.5rem, 7vw, 6rem) var(--s-6);
}

/* Top band: identity on the left, the one action we want on the right. */
.footer__top {
  display: grid;
  gap: var(--s-6);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
  border-bottom: 1px solid var(--rule-on-dark);
}

@media (min-width: 62rem) {
  .footer__top {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--s-8);
  }
}

.footer__brand {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 1;
}

.footer__tag {
  margin-top: var(--s-4);
  color: var(--fg-on-dark-mut);
  font-size: var(--t-sm);
  max-width: 36ch;
}

.footer__reach {
  display: grid;
  gap: var(--s-3);
  justify-items: start;
}

@media (min-width: 62rem) {
  .footer__reach { justify-items: end; text-align: right; }
}

.footer__phone {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  transition: color var(--dur-2) var(--ease-out);
}
.footer__phone:hover { color: var(--nv-blue-bright); }

.footer__phonenote {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-on-dark-fnt);
}

.footer__reach .btn { margin-top: var(--s-2); }

/* Link columns */
.footer__grid {
  display: grid;
  gap: var(--s-7) var(--s-6);
  padding-top: clamp(2.5rem, 5vw, 3.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
}

/* On a phone the auto-fit track falls back to one column and the footer turns
   into a very long ladder, so it is pinned to two. */
@media (max-width: 47.99rem) {
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-6) var(--s-4);
  }
}

.footer__h {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--fg-on-dark-fnt);
  margin-bottom: var(--s-4);
}

.footer__list { display: grid; gap: var(--s-3); }

.footer__list a,
.footer__list li {
  font-size: var(--t-sm);
  color: var(--fg-on-dark-mut);
  line-height: 1.45;
}

.footer__list a {
  position: relative;
  display: inline-block;
  transition: color var(--dur-2) var(--ease-out),
              transform var(--dur-2) var(--ease-out);
}
.footer__list a:hover {
  color: #fff;
  transform: translateX(3px);
}

.footer__list--plain li { color: var(--fg-on-dark-fnt); }

.footer__address {
  font-style: normal;
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--fg-on-dark-mut);
}

.footer__mail {
  display: inline-block;
  margin-top: var(--s-3);
  font-size: var(--t-sm);
  color: var(--nv-blue-bright);
  word-break: break-word;
  transition: color var(--dur-2) var(--ease-out);
}
.footer__mail:hover { color: #fff; }

/* Bottom bar */
.footer__bar {
  margin-top: clamp(3rem, 6vw, 4.5rem);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule-on-dark);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3) var(--s-5);
}

.footer__bar-mid { display: none; }
@media (min-width: 62rem) { .footer__bar-mid { display: inline; } }

.footer__top-link {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  transition: color var(--dur-2) var(--ease-out);
}
.footer__top-link:hover { color: #fff; }
.footer__top-link svg { transition: transform var(--dur-2) var(--ease-out); }
.footer__top-link:hover svg { transform: translateY(-3px); }

.footer__credit { transition: color var(--dur-2) var(--ease-out); }
.footer__credit:hover { color: #fff; }
@media (prefers-reduced-motion: reduce) {
  .footer__credit { transition: none; }
}

/* --------------------------------------------------------------------------
   13. Contact form
   -------------------------------------------------------------------------- */

.form { display: grid; gap: var(--s-4); }

.field { display: grid; gap: var(--s-2); }

.field__row {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
}

.field label {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.field label .req { color: var(--nv-blue); }

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.8rem 1rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-sm);
  background: var(--nv-paper);
  font-size: var(--t-body);
  transition: border-color var(--dur-2) var(--ease-out),
              box-shadow var(--dur-2) var(--ease-out);
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--nv-blue);
  box-shadow: 0 0 0 3px rgba(26, 109, 255, 0.15);
}

.field textarea { min-height: 8rem; resize: vertical; }

.form__note {
  font-size: var(--t-xs);
  color: var(--fg-faint);
}

/* --------------------------------------------------------------------------
   14. Utilities
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
}
@media (min-width: 62rem) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; }
  .split--wide { grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); align-items: start; }
  .split--sticky { align-items: start; }
  .split--sticky > :first-child { position: sticky; top: 7rem; }
}

.stack { display: grid; gap: var(--s-4); }
.stack--lg { gap: var(--s-6); }

.list-check { display: grid; gap: var(--s-3); }
.list-check li {
  position: relative;
  padding-left: 1.6rem;
  font-size: var(--t-sm);
  line-height: 1.6;
  color: var(--fg-muted);
}
/* A drawn tick rather than a bullet: the list is a list of things that are
   done, and a square dot on every line turns a long list into wallpaper. */
.list-check li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.45em;
  width: 0.3rem;
  height: 0.6rem;
  border-right: 1.5px solid var(--nv-blue);
  border-bottom: 1.5px solid var(--nv-blue);
  transform: rotate(42deg);
}
.section--dark .list-check li::before {
  border-right-color: var(--nv-blue-bright);
  border-bottom-color: var(--nv-blue-bright);
}
.section--dark .list-check li { color: var(--fg-on-dark-mut); }

.cols-2 { columns: 1; column-gap: var(--s-7); }
@media (min-width: 48rem) { .cols-2 { columns: 2; } }
.cols-2 li { break-inside: avoid; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   15. Why - editorial argument
   Two moves: the statement, then the body split into argument and duties.
   No photograph here: the team shot carries the hero, so this section stays
   pure type and the figures below it land harder.
   -------------------------------------------------------------------------- */

.why__statement {
  font-family: var(--font-display);
  /* Sized to fill the container rather than sit in a narrow column. The scale
     is what makes it span the full measure, not a width cap. */
  font-size: clamp(1.875rem, 5.2vw, 4.25rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.036em;
  text-wrap: balance;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}

.why__statement .hl { color: var(--nv-blue); }

.why__body {
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem);
}

@media (min-width: 62rem) {
  .why__body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(3rem, 6vw, 6rem);
  }
}

/* The measure lives on the container, not on each paragraph. A ch-based cap
   on each one gives them different pixel widths whenever their font sizes
   differ, which is what made the right edge look ragged. */
.why__lead {
  display: grid;
  gap: var(--s-5);
  align-content: start;
  max-width: 36rem;
}

.why__lead p {
  font-size: clamp(1rem, 1.15vw, 1.0625rem);
  line-height: 1.62;
  max-width: none;
}

.why__lead .lead { color: var(--fg); }
.why__lead .muted { color: var(--fg-muted); }

/* Numbered responsibilities. Hairline above each row, none below the last,
   so the group reads as one block instead of a boxed table. */
.duties { display: grid; }

.duty {
  position: relative;
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  gap: var(--s-4);
  align-items: baseline;
  padding: clamp(0.9rem, 1.8vw, 1.25rem) var(--s-4);
  margin-inline: calc(var(--s-4) * -1);
  border-top: 1px solid var(--rule);
  border-radius: var(--r-sm);
  transition: background-color var(--dur-2) var(--ease-out);
}
.duty:last-child { border-bottom: 1px solid var(--rule); }

/* A blue rule grows down the left edge of the row under the cursor. It marks
   where the reader is in the list; the list itself is not clickable. */
.duty::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 2px;
  border-radius: 2px;
  background: var(--nv-blue);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--dur-3) var(--ease-out);
}

.duty__n {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.12em;
  color: var(--fg-faint);
  transition: color var(--dur-2) var(--ease-out);
}

.duty__t {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.5vw, 1.1875rem);
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.34;
  text-wrap: pretty;
  transition: transform var(--dur-2) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .duty:hover { background: var(--nv-blue-tint); }
  .duty:hover::before { transform: scaleY(1); }
  .duty:hover .duty__n { color: var(--nv-blue); }
  .duty:hover .duty__t { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .duty::before { transition: none; }
  .duty__t { transition: none; }
}

/* --------------------------------------------------------------------------
   16. Codes section header - the headline needs room, the side note does not
   -------------------------------------------------------------------------- */

.sec-head--codes {
  display: grid;
  gap: var(--s-5);
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}

@media (min-width: 62rem) {
  .sec-head--codes {
    /* 1.6fr against 1fr: the headline gets the space it needs to sit on two
       lines instead of three, and the note stays a note. */
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    align-items: end;
    gap: clamp(2.5rem, 5vw, 5rem);
  }
}

.sec-head--codes .display--1 { max-width: 18ch; }
.sec-head--codes .lead { max-width: 48ch; }

/* --------------------------------------------------------------------------
   17. Service rows - the photograph arrives on hover
   Keeps the list scannable as type, and rewards the row the reader is
   actually on. The column still reserves its space, so nothing shifts.
   -------------------------------------------------------------------------- */

@media (hover: hover) and (pointer: fine) and (min-width: 62rem) {
  .srv__media {
    opacity: 0;
    transform: translateX(1.25rem) scale(0.94);
    transition: opacity var(--dur-3) var(--ease-out),
                transform var(--dur-3) var(--ease-out);
  }

  .srv:hover .srv__media,
  .srv:focus-within .srv__media {
    opacity: 1;
    transform: translateX(0) scale(1);
  }

  /* The row itself dims its neighbours so the hovered one reads as active. */
  .srv__no,
  .srv__title,
  .srv__desc,
  .srv .chip-row {
    transition: opacity var(--dur-2) var(--ease-out),
                color var(--dur-2) var(--ease-out);
  }

  .srv-list:hover .srv:not(:hover) .srv__no,
  .srv-list:hover .srv:not(:hover) .srv__title,
  .srv-list:hover .srv:not(:hover) .srv__desc,
  .srv-list:hover .srv:not(:hover) .chip-row {
    opacity: 0.42;
  }
}

@media (prefers-reduced-motion: reduce) {
  .srv__media { opacity: 1 !important; transform: none !important; }
}

/* --------------------------------------------------------------------------
   18. No eyebrows
   Section label strips are gone. Sections are separated by their own
   background and spacing, so each one opens straight on its headline.
   -------------------------------------------------------------------------- */

.trust-note {
  text-align: center;
  margin-bottom: var(--s-6);
  font-size: var(--t-sm);
  color: var(--fg-muted);
}

/* The hero headline carried the eyebrow's top margin. Put it back. */
.hero__title { margin-top: 0; }

/* Sections that opened with a rail need their own top breathing room. */
.why__statement { margin-top: 0; }

/* --------------------------------------------------------------------------
   19. Nav services group
   Four top-level items instead of six. The service pages live one level down,
   which is also where the remaining service pages will go as they are built.
   -------------------------------------------------------------------------- */

.nav__group { position: relative; }

.nav__link--btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
}

.nav__caret { transition: transform var(--dur-2) var(--ease-out); }
.nav__link--btn[aria-expanded="true"] .nav__caret { transform: rotate(180deg); }
.nav__link--btn[aria-expanded="true"] { opacity: 1; }

.nav__menu {
  position: absolute;
  top: calc(100% + 0.625rem);
  left: 50%;
  min-width: 15rem;
  padding: var(--s-2);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, 0.97);
  border: 1px solid var(--rule);
  box-shadow: var(--shadow-lg);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  display: grid;
  gap: 2px;

  transform: translate(-50%, -6px) scale(0.97);
  transform-origin: top center;
  opacity: 0;
  visibility: hidden;
  transition: transform var(--dur-3) var(--ease-out),
              opacity var(--dur-2) var(--ease-out),
              visibility 0s linear var(--dur-3);
}

.nav__menu.is-open {
  transform: translate(-50%, 0) scale(1);
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}

.nav__menu a {
  padding: 0.55rem 0.75rem;
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  color: var(--nv-black);
  white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out),
              color var(--dur-1) var(--ease-out);
}
.nav__menu a:hover {
  background: var(--nv-blue-tint);
  color: var(--nv-blue);
}

.codes__foot {
  margin-top: var(--s-5);
  font-size: var(--t-sm);
}

/* --------------------------------------------------------------------------
   20. Stat hover
   The figure under the cursor comes forward with a tint and a blue rule on
   its own grid border. A white card plus shadow was tried first and read as a
   panel that had broken out of the grid, so the cell stays in its row.
   -------------------------------------------------------------------------- */

.stat {
  position: relative;
  transition: background-color var(--dur-2) var(--ease-out);
}

.stat::after {
  content: "";
  position: absolute;
  left: -1px;
  top: -1px;
  bottom: -1px;
  width: 2px;
  background: var(--nv-blue);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--dur-3) var(--ease-out);
}

.stat__num,
.stat__label {
  position: relative;
  transition: transform var(--dur-3) var(--ease-out),
              color var(--dur-2) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .stat:hover { background: var(--nv-blue-tint); }
  .stat:hover::after { transform: scaleY(1); }
  .stat:hover .stat__num { transform: translateY(-2px); }
  .stat:hover .stat__label { color: var(--fg); }
}

@media (prefers-reduced-motion: reduce) {
  .stat::after,
  .stat__num,
  .stat__label { transition: none; }
  .stat:hover .stat__num { transform: none; }
}

/* --------------------------------------------------------------------------
   21. Capabilities - the eight areas between the figures and the disciplines
   A quiet type grid on white. Each cell is ruled at the top only, so the
   section reads as a list of work rather than a wall of cards.
   -------------------------------------------------------------------------- */

.sec-head--caps {
  display: grid;
  gap: var(--s-4);
  margin-bottom: clamp(2rem, 4vw, 3.25rem);
}

@media (min-width: 62rem) {
  .sec-head--caps {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    align-items: end;
    gap: clamp(2.5rem, 5vw, 5rem);
  }
}

.sec-head--caps .display--1 { max-width: 16ch; }
.sec-head--caps .lead { max-width: 46ch; }

.caps__grid {
  /* The outdent lives on the grid, not on each cell. Putting it on the cells
     made every cell overlap its neighbour by a full padding on each side,
     which is what pushed the hover tint into the next column and collided
     the body copy. */
  --cap-pad: clamp(0.875rem, 1.6vw, 1.25rem);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  margin-inline: calc(var(--cap-pad) * -1);
}

@media (min-width: 40rem) {
  .caps__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 62rem) {
  .caps__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.cap {
  position: relative;
  padding: clamp(1.1rem, 2.2vw, 1.5rem) var(--cap-pad);
  border-radius: var(--r-sm);
  transition: background-color var(--dur-2) var(--ease-out);
}

/* Hairline inset to the text edge so the rules line up with the copy rather
   than with the padded hover area. */
.cap::after {
  content: "";
  position: absolute;
  top: 0;
  left: var(--cap-pad);
  right: var(--cap-pad);
  height: 1px;
  background: var(--rule);
}

/* The blue rule rides the same inset edge on the cell under the cursor. */
.cap::before {
  content: "";
  position: absolute;
  z-index: 1;
  top: 0;
  left: var(--cap-pad);
  right: var(--cap-pad);
  height: 2px;
  background: var(--nv-blue);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-3) var(--ease-out);
}

.cap__n {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.12em;
  color: var(--fg-faint);
  transition: color var(--dur-2) var(--ease-out);
}

.cap__t {
  margin-top: var(--s-3);
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.4vw, 1.125rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  transition: color var(--dur-2) var(--ease-out);
}

.cap__d {
  margin-top: var(--s-2);
  font-size: var(--t-sm);
  color: var(--fg-muted);
  line-height: 1.5;
  text-wrap: pretty;
}

@media (hover: hover) and (pointer: fine) {
  .cap:hover { background: var(--nv-blue-tint); }
  .cap:hover::before { transform: scaleX(1); }
  .cap:hover .cap__n { color: var(--nv-blue); }
  .cap:hover .cap__t { color: var(--nv-blue); }
}

@media (prefers-reduced-motion: reduce) {
  .cap,
  .cap::before,
  .cap__n,
  .cap__t { transition: none; }
  .cap:hover::before { transform: none; }
}

/* --------------------------------------------------------------------------
   20. "What the service covers" panel (about page, expertise section)
   The list used to sit naked on the tinted section next to a column of prose,
   so it read as a footnote instead of the spec sheet it actually is. It now
   takes the same treatment the deduction-code table already uses on a tinted
   section: white paper, one rule, ruled rows.
   -------------------------------------------------------------------------- */

.covers {
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  background: var(--nv-paper);
  /* clip so the rows' own rules stop at the rounded corners */
  overflow: clip;
}

.covers__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) clamp(1rem, 2.2vw, 1.5rem);
  border-bottom: 1px solid var(--rule);
}

/* --fg-faint disappeared against the panel; the label is the block's title. */
.covers__head .meta { color: var(--fg-muted); }

.covers__count {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  color: var(--fg-faint);
}

.covers__list {
  display: grid;
}

.covers__list li {
  /* a real column for the tick, not padding-left + an absolute box: the long
     last item wrapped back under its own tick before. */
  display: grid;
  grid-template-columns: 0.75rem minmax(0, 1fr);
  gap: var(--s-3);
  align-items: start;
  padding: 0.8rem clamp(1rem, 2.2vw, 1.5rem);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm);
  line-height: 1.55;
  color: var(--fg);
}

.covers__list li:first-child { border-top: 0; }

.covers__list li::before {
  content: "";
  width: 0.3rem;
  height: 0.6rem;
  margin-top: 0.34em;
  justify-self: center;
  border-right: 1.5px solid var(--nv-blue);
  border-bottom: 1.5px solid var(--nv-blue);
  transform: rotate(42deg);
}


/* --------------------------------------------------------------------------
   Stacked sections
   Opt-in only. Wrap the pair in .stack-sections, give the section that should
   hold still .stack-pin, and the one that rides up over it .stack-over. The
   wrapper is what bounds the sticky range, so the pinned section is released
   the moment the pair is done - it never bleeds under later sections.
   (Unrelated to .stack above, which is a vertical-rhythm grid utility.)
   -------------------------------------------------------------------------- */

.stack-sections { position: relative; }

@media (min-width: 62rem) {
  .stack-pin {
    position: sticky;
    /* Set by main.js: 0 for a short section, negative for one taller than the
       viewport so it scrolls to its own end before it holds. */
    top: var(--stack-top, 0px);
    z-index: 0;
    background: var(--bg);
  }

  .stack-pin.section--alt { background: var(--bg-alt); }
  .stack-pin.section--dark { background: var(--bg-dark); }

  .stack-over {
    position: relative;
    z-index: 1;
    border-start-start-radius: var(--r-xl);
    border-start-end-radius: var(--r-xl);
    box-shadow: 0 -1.5rem 3.5rem rgba(10, 11, 13, 0.28);
  }
}

@media (prefers-reduced-motion: reduce) {
  .stack-pin { position: relative; top: auto; }
  .stack-over { border-radius: 0; box-shadow: none; }
}

/* --------------------------------------------------------------------------
   Mobile sliders
   Two long stacks - the four services and the team - turn into swipeable rows
   on a phone. Scroll snap only, no library: native momentum, keyboard and
   trackpad all keep working. The next card is left half in view so the row
   reads as something you can move.
   -------------------------------------------------------------------------- */

@media (max-width: 47.99rem) {
  .srv-list,
  .team-grid {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--s-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Bleed to the screen edges, so a card can sit half off it. */
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    /* The row needs to breathe under the section head before it starts. */
    margin-top: clamp(2rem, 6vw, 2.75rem);
    padding-block: var(--s-2);
  }

  .srv-list::-webkit-scrollbar,
  .team-grid::-webkit-scrollbar { display: none; }

  .srv-list > *,
  .team-grid > * {
    flex: 0 0 82%;
    scroll-snap-align: start;
    /* A row that scrolls sideways cannot also rise into view: cards waiting
       off the right edge would sit invisible until they were swiped to. */
    opacity: 1;
    transform: none;
  }

  .srv-list { border-bottom: 0; }

  .srv {
    border: 1px solid var(--rule-on-dark);
    border-radius: var(--r-lg);
    padding: var(--s-5);
  }

  .team-grid { gap: var(--s-4); }
}
