.zl-nav {
  position: relative;
  z-index: 10;
  min-height: var(--zl-nav-height);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zl-space-6);
  padding-inline: clamp(1.25rem, 3.4vw, 4rem);
  border-bottom: 1px solid var(--zl-line);
  background: var(--zl-surface-a92);
}

.zl-wordmark {
  color: var(--zl-ink);
  font-family: var(--zl-font-display);
  font-size: 1.35rem;
  font-weight: var(--zl-weight-bold);
  letter-spacing: var(--zl-tracking-display);
  text-decoration: none;
}
/* The supplied mark is a 500x500 square logomark, so it locks up beside the
   wordmark rather than replacing it. Its paths are hardcoded near-black, so the
   dark footer inverts it rather than recolouring. */
.zl-wordmark { display: inline-flex; align-items: center; gap: .55rem; }
.zl-wordmark__mark { width: 1.6em; height: 1.6em; flex: 0 0 auto; }
.zl-wordmark--mark-only .zl-wordmark__mark { width: 2.1em; height: 2.1em; }


.zl-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--zl-space-3);
  color: var(--zl-muted-text);
  font-family: var(--zl-font-mono);
  font-size: var(--zl-text-xs);
  font-weight: var(--zl-weight-bold);
  letter-spacing: var(--zl-tracking-label);
  line-height: 1.2;
  text-transform: uppercase;
}

.zl-eyebrow::before {
  width: 1.5rem;
  height: 1px;
  background: currentColor;
  content: "";
}

.zl-eyebrow[data-tone="grow"] {
  color: var(--zl-vermilion-text);
}

.zl-eyebrow[data-tone="build"] {
  color: var(--zl-cobalt);
}

.zl-button-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--zl-space-3);
}

.zl-button {
  min-height: 3.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--zl-space-6);
  padding: 0.95rem 1.35rem;
  border: 1px solid transparent;
  border-radius: var(--zl-radius-none);
  background: var(--zl-ink);
  color: var(--zl-on-dark);
  font-family: var(--zl-font-ui);
  font-weight: var(--zl-weight-bold);
  line-height: 1;
  text-decoration: none;
  transition:
    background var(--zl-duration-fast) var(--zl-ease-standard),
    color var(--zl-duration-fast) var(--zl-ease-standard),
    transform var(--zl-duration-fast) var(--zl-ease-standard);
}

.zl-button:hover {
  background: var(--zl-surface);
  color: var(--zl-ink);
  transform: translateY(-2px);
}

.zl-button--secondary {
  border-color: var(--zl-line-strong);
  border-style: dashed;
  background: transparent;
  color: var(--zl-ink);
}

.zl-button--secondary:hover {
  background: var(--zl-ink);
  color: var(--zl-on-dark);
}


.zl-data-pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--zl-space-2);
}

.zl-data-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--zl-space-2);
  min-height: 2rem;
  padding-inline: 0.8rem;
  border: 1px solid var(--zl-line-strong);
  border-radius: var(--zl-radius-pill);
  background: var(--zl-surface);
  color: var(--zl-body);
  font-family: var(--zl-font-mono);
  font-size: var(--zl-text-xs);
}

.zl-data-pill::before {
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: var(--zl-muted);
  content: "";
}

.zl-data-pill[data-tone="grow"]::before {
  background: var(--zl-vermilion);
}

.zl-data-pill[data-tone="build"]::before {
  background: var(--zl-cobalt);
}

.zl-panel {
  position: relative;
  overflow: hidden;
  padding: clamp(1.5rem, 3vw, 3rem);
  border: 1px solid var(--zl-line);
  background:
    linear-gradient(var(--zl-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--zl-line) 1px, transparent 1px),
    var(--zl-surface);
  background-size: 2rem 2rem;
}

.zl-panel::after {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--zl-surface) 18%, transparent 70%);
  content: "";
  pointer-events: none;
}

.zl-panel > * {
  position: relative;
  z-index: 1;
}

.zl-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-block: 1px solid var(--zl-line);
}

.zl-metric {
  min-height: 9rem;
  padding: var(--zl-space-6);
  border-right: 1px solid var(--zl-line);
}

.zl-metric:last-child {
  border-right: 0;
}

.zl-metric__value {
  display: block;
  color: var(--zl-ink);
  font-size: clamp(2rem, 4vw, 3.5rem);
  letter-spacing: -0.055em;
  line-height: 1;
}

.zl-metric__label {
  display: block;
  margin-top: var(--zl-space-3);
  color: var(--zl-muted-text);
  font-size: var(--zl-text-sm);
}

.zl-paths {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border: 1px solid var(--zl-line);
}

.zl-path {
  min-height: 17rem;
  padding: clamp(1.5rem, 3vw, 3rem);
  background: var(--zl-surface);
}

.zl-path + .zl-path {
  border-left: 1px solid var(--zl-line);
}

.zl-path[data-tone="build"] {
  box-shadow: inset 0 3px 0 var(--zl-cobalt);
}

.zl-path[data-tone="grow"] {
  box-shadow: inset 0 3px 0 var(--zl-vermilion);
}

@media (max-width: 46rem) {
  .zl-nav {
    min-height: 4rem;
    padding-inline: 0;
  }

  .zl-metrics,
  .zl-paths {
    grid-template-columns: 1fr;
  }

  .zl-metric,
  .zl-metric:last-child {
    border-right: 0;
    border-bottom: 1px solid var(--zl-line);
  }

  .zl-metric:last-child {
    border-bottom: 0;
  }

  .zl-path + .zl-path {
    border-top: 1px solid var(--zl-line);
    border-left: 0;
  }
}

/* ------------------------------------------------------------------
   CTA pair — the page's one call-to-action component.
   Primary fills cobalt on hover and rotates its arrow a quarter turn.
   Secondary is drawn with four repeating gradients so the dashed border
   reads hand-made, and turns cobalt on hover. These rules were previously
   scoped to .hero__actions, so every other instance on the page got only
   half the treatment.
   ------------------------------------------------------------------ */
.zl-cta {
  min-width: 12.75rem;
  display: inline-flex;
  justify-self: start;
  align-items: center;
  justify-content: space-between;
  gap: .6rem;
  padding: .7rem .75rem .7rem 1.35rem;
  transform: none;
  transition:
    background-color var(--zl-duration-medium) var(--zl-ease-standard),
    color var(--zl-duration-medium) var(--zl-ease-standard);
}
.zl-cta__label { position: relative; z-index: 1; }
.zl-cta__arrow {
  width: 2rem;
  height: 2rem;
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  background: transparent;
  transition:
    background-color var(--zl-duration-medium) var(--zl-ease-standard),
    transform var(--zl-duration-medium) var(--zl-ease-standard);
}
.zl-cta__arrow svg { width: 2rem; height: 2rem; fill: currentColor; }

.zl-cta--primary:hover,
.zl-cta--primary:focus-visible { background-color: var(--zl-cobalt); color: var(--zl-on-dark); transform: none; }
.zl-cta--primary:hover .zl-cta__arrow,
.zl-cta--primary:focus-visible .zl-cta__arrow {
  background-color: var(--zl-on-dark-a12);
  transform: rotate(-90deg);
}

.zl-cta--secondary {
  border: 0;
  background-color: transparent;
  background-image:
    repeating-linear-gradient(-13deg, var(--zl-line-strong), var(--zl-line-strong) 11px, transparent 11px, transparent 18px, var(--zl-line-strong) 18px),
    repeating-linear-gradient(77deg, var(--zl-line-strong), var(--zl-line-strong) 11px, transparent 11px, transparent 15px, var(--zl-line-strong) 18px),
    repeating-linear-gradient(167deg, var(--zl-line-strong), var(--zl-line-strong) 11px, transparent 11px, transparent 15px, var(--zl-line-strong) 18px),
    repeating-linear-gradient(257deg, var(--zl-line-strong), var(--zl-line-strong) 11px, transparent 11px, transparent 18px, var(--zl-line-strong) 18px);
  background-position: 0 0, 0 0, 100% 0, 0 100%;
  background-repeat: no-repeat;
  background-size: 1px 100%, 100% 1px, 1px 100%, 100% 1px;
  color: var(--zl-muted-text);
}
/* .zl-button--secondary:hover uses the `background` shorthand, which resets
   background-size to auto and has higher specificity than the base rule that
   sizes the border gradients to 1px strips. Left alone, the dashed border
   paints at full size on hover -- a solid block behind dark text. So the hover
   state drops the gradients outright and fills, with light text over it. */
.zl-cta--secondary:hover,
.zl-cta--secondary:focus-visible {
  background-color: var(--zl-cobalt);
  background-image: none;
  color: var(--zl-on-dark);
  transform: none;
}

/* Compact size for the nav bar. Same component, 44px box: the 204px min-width
   and the arrow-side padding both come off because nav buttons are label-only.
   Declared after .zl-cta so it wins on source order -- both are single-class
   selectors. Everything that makes a button look like a ZipLabs button (the
   drawn dashed border, the cobalt hover, the type) still comes from the
   component, so the nav cannot drift from the body buttons again. */
.zl-cta--compact {
  min-width: 0;
  min-height: 2.75rem;
  justify-content: center;
  gap: var(--zl-space-3);
  padding: 0.6rem 1rem;
  font-size: var(--zl-text-sm);
}

/* on the ink band the same component inverts */
.zl-cta--on-dark.zl-cta--primary { background-color: var(--zl-surface); color: var(--zl-ink); }
.zl-cta--on-dark.zl-cta--primary:hover,
.zl-cta--on-dark.zl-cta--primary:focus-visible { background-color: var(--zl-cobalt); color: var(--zl-on-dark); }
.zl-cta--on-dark.zl-cta--secondary {
  background-image:
    repeating-linear-gradient(-13deg, var(--zl-on-dark-a45), var(--zl-on-dark-a45) 11px, transparent 11px, transparent 18px, var(--zl-on-dark-a45) 18px),
    repeating-linear-gradient(77deg, var(--zl-on-dark-a45), var(--zl-on-dark-a45) 11px, transparent 11px, transparent 15px, var(--zl-on-dark-a45) 18px),
    repeating-linear-gradient(167deg, var(--zl-on-dark-a45), var(--zl-on-dark-a45) 11px, transparent 11px, transparent 15px, var(--zl-on-dark-a45) 18px),
    repeating-linear-gradient(257deg, var(--zl-on-dark-a45), var(--zl-on-dark-a45) 11px, transparent 11px, transparent 18px, var(--zl-on-dark-a45) 18px);
  color: var(--zl-on-dark);
}
.zl-cta--on-dark.zl-cta--secondary:hover,
.zl-cta--on-dark.zl-cta--secondary:focus-visible {
  background-color: var(--zl-cobalt);
  background-image: none;
  color: var(--zl-on-dark);
}

@media (prefers-reduced-motion: reduce) {
  .zl-cta, .zl-cta__arrow { transition: none; }
  .zl-cta--primary:hover .zl-cta__arrow { transform: none; }
}

/* ------------------------------------------------------------------
   Site header — shared by the landing page and every subpage.
   Lived in hero.css until now, which meant the legal pages rendered it
   unstyled. Markup is generated from partials/site-nav.html.
   ------------------------------------------------------------------ */
/* Sticky: the bar already carried z-index, a translucent surface and a blur,
   so it was built for this. Height is exposed as --zl-nav-height for anything
   that needs to offset scroll targets beneath it. */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 20;
  min-height: var(--zl-nav-height);
  /* Flex, not grid: display:none removes the link row from the grid entirely,
     which dropped the actions into the 1fr track and stretched them to 639px
     and left-aligned. space-between keeps the mark left and actions right
     whether or not the middle row is present. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  padding-inline: clamp(1.25rem, 3.4vw, 4rem);
  background: var(--zl-surface-a94);
  backdrop-filter: blur(12px);
}
/* The rule bleeds past the frame while the bar's own surface does not -- the
   same split .section-divider uses, where the hatch stops at the frame and the
   lines carry on to the viewport edge. Sticky already establishes the
   positioning context this needs. */
.site-nav::after {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 100vw;
  height: 1px;
  transform: translateX(-50%);
  background: var(--zl-line);
  content: "";
  pointer-events: none;
}
.site-nav > .zl-wordmark { flex: 0 0 auto; }
/* Stretched, not centred: the row is the positioning context the Solutions
   dropdown hangs off, and a content-height row (21.7px inside a 72px bar) put
   the panel's top edge a quarter of the way up the bar instead of below it. */
.site-nav__links { flex: 0 1 auto; align-self: stretch; }
.site-nav__actions { flex: 0 0 auto; margin-left: auto; }

.site-nav a {
  text-decoration: none;
}

.site-nav__links,
.site-nav__actions {
  display: flex;
  align-items: center;
}

.site-nav__links {
  gap: clamp(1.25rem, 2.4vw, 2.5rem);
}

.site-nav__links a {
  color: var(--zl-body);
  font-size: var(--zl-text-sm);
  transition: color var(--zl-duration-fast) var(--zl-ease-standard);
}

.site-nav__links a:hover {
  color: var(--zl-ink);
}

.site-nav__actions {
  gap: var(--zl-space-3);
}

/* .site-nav__login / .site-nav__cta carry no appearance of their own -- they
   are layout and breakpoint hooks only. The buttons get their look from
   .zl-button + .zl-button--secondary + .zl-button--compact in the markup. */

/* Solutions dropdown. The group is stretched to the full bar height so the
   panel can hang off `top: 100%` with no dead gap between trigger and menu --
   a gap is what makes hover menus feel broken when the pointer crosses it.
   Open state is driven by :hover, :focus-within and [data-open], so pointer,
   keyboard and touch all reach it; visibility (not display) keeps the
   transition and keeps the links out of the tab order while closed. */
.site-nav__group {
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
}

.site-nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--zl-body);
  font: inherit;
  font-size: var(--zl-text-sm);
  line-height: inherit;
  cursor: pointer;
  transition: color var(--zl-duration-fast) var(--zl-ease-standard);
}

.site-nav__group:hover .site-nav__trigger,
.site-nav__group:focus-within .site-nav__trigger,
.site-nav__trigger[aria-expanded="true"] { color: var(--zl-ink); }

.site-nav__chevron {
  transition: transform var(--zl-duration-fast) var(--zl-ease-standard);
}

.site-nav__group:hover .site-nav__chevron,
.site-nav__group:focus-within .site-nav__chevron,
.site-nav__group[data-open="true"] .site-nav__chevron,
.site-nav__trigger[aria-expanded="true"] .site-nav__chevron { transform: rotate(180deg); }

.site-nav__dropdown {
  position: absolute;
  top: 100%;
  left: -1rem;
  z-index: 1;
  display: grid;
  gap: 2px;
  min-width: 15.5rem;
  padding: .5rem;
  border: 1px solid var(--zl-line);
  border-radius: 3px;
  background: var(--zl-surface);
  box-shadow: 0 18px 40px -24px rgb(28 27 23 / .38);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition:
    opacity var(--zl-duration-fast) var(--zl-ease-standard),
    transform var(--zl-duration-fast) var(--zl-ease-standard),
    visibility 0s linear var(--zl-duration-fast);
}

.site-nav__group:hover .site-nav__dropdown,
.site-nav__group:focus-within .site-nav__dropdown,
.site-nav__group[data-open="true"] .site-nav__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

.site-nav__dropdown a {
  position: relative;
  display: grid;
  gap: 1px;
  padding: .6rem .75rem .6rem 1rem;
  border-radius: 2px;
  transition:
    background var(--zl-duration-fast) var(--zl-ease-standard),
    transform var(--zl-duration-fast) var(--zl-ease-standard);
}

/* The wiping accent bar that used to live here was removed [Arjun, 2026-08-07]:
   the corner frame now follows the pointer across the whole menu, and a second
   mark appearing on the same card at the same moment said the same thing twice.
   The 3px slide went with it — the frame is the response to the pointer now,
   and the slide dragged the outgoing frame sideways mid-travel, contaminating
   the very direction the travel exists to express. The background stays. */
.site-nav__dropdown a:hover,
.site-nav__dropdown a:focus-visible { background: var(--zl-bg); }

.site-nav__dropdown-title {
  color: var(--zl-ink);
  font-size: var(--zl-text-sm);
  transition: color var(--zl-duration-fast) var(--zl-ease-standard);
}

.site-nav__dropdown-note {
  color: var(--zl-muted);
  font-size: var(--zl-text-xs);
  transition: color var(--zl-duration-fast) var(--zl-ease-standard);
}

.site-nav__dropdown a:hover .site-nav__dropdown-note,
.site-nav__dropdown a:focus-visible .site-nav__dropdown-note { color: var(--zl-body); }

/* ── The description, typed out on hover ──────────────────────────────────
   [Arjun, 2026-08-07] A card grows DOWNWARD to a brief description, typed in,
   and holds it while the card has the pointer or focus.

   Height animates on grid-template-rows 0fr -> 1fr rather than max-height,
   because the row measures itself: no magic pixel ceiling to guess, and no
   ceiling that silently clips a description someone lengthens later.

   The columns are fixed width, not max-content -- see .site-nav__mega. A
   description is far longer than any title, so under max-content it would
   have widened the panel instead of growing the card, which is the opposite
   of what was asked for.

   aria-hidden: the link's accessible name is already "title + note", and
   appending a sentence to each would make the menu read like prose. The text
   is in the DOM and crawlable regardless. */
.site-nav__dropdown-desc {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows var(--zl-nav-desc) var(--zl-ease-standard);
}
.site-nav__dropdown a.is-open .site-nav__dropdown-desc { grid-template-rows: 1fr; }

.site-nav__dropdown-desc > span {
  min-height: 0;      /* or the row refuses to go below its content height */
  padding-top: .3rem;
  color: var(--zl-muted);
  font-size: var(--zl-text-xs);
  line-height: 1.5;
}

/* The untyped remainder stays in the layout and is merely invisible, so the
   card settles at its final height on the first frame and the text wraps
   exactly where it will end up. Retyping into an empty box would reflow on
   nearly every character and shuffle the line breaks as it went. */
.site-nav__dropdown-rest { color: transparent; }

/* The caret sits at the boundary between typed and untyped, which is exactly
   where this pseudo-element lands. It is 1px of constant width whether or not
   anything remains to type, so it never moves the text it sits in. */
.site-nav__dropdown-rest::before {
  display: inline-block;
  width: 1px;
  height: .75em;
  margin-right: 1px;
  transform: translateY(.1em);
  background: var(--zl-vermilion);
  animation: nav-caret 1.1s steps(1) infinite;
  content: "";
}

@keyframes nav-caret { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .site-nav__dropdown a,
  .site-nav__dropdown,
  .site-nav__dropdown-desc { transition: none; }
  /* The description still appears -- it is content, not decoration. It simply
     arrives whole instead of being typed, and the caret stops blinking. */
  .site-nav__dropdown-rest::before { animation: none; opacity: 0; }
}

/* 48rem, not 64rem: measured, the link row needs 311px and the whole bar fits
   inline down to ~710px, so collapsing at 1024px hid navigation that had room. */
@media (max-width: 48rem) {
  .site-nav__links { display: none; }
}

@media (max-width: 48rem) {
  .site-nav { padding-inline: 1rem; }
  .site-nav__login { display: none; }
  .site-nav__cta { min-height: 2.5rem; padding-inline: 0.85rem; }
}


/* Mobile menu. Hidden above 64rem, where the inline links are visible. The
   panel is a sibling of the grid tracks and spans the full bar width beneath
   it; `hidden` is the closed state so it stays inert without JS. */
.site-nav__toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 1px solid var(--zl-line);
  border-radius: 2px;
  background: transparent;
  color: var(--zl-ink);
  cursor: pointer;
}
.site-nav__toggle-bars { display: grid; gap: 4px; width: 1rem; }
.site-nav__toggle-bars i {
  display: block;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--zl-duration-fast) var(--zl-ease-standard),
              opacity var(--zl-duration-fast) var(--zl-ease-standard);
}
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-bars i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-bars i:nth-child(2) { opacity: 0; }
.site-nav__toggle[aria-expanded="true"] .site-nav__toggle-bars i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.site-nav__menu {
  flex: 0 0 100%;
  order: 1;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-inline: calc(-1 * clamp(1.25rem, 3.4vw, 4rem));
  padding: .5rem clamp(1.25rem, 3.4vw, 4rem) 1.25rem;
  border-top: 1px solid var(--zl-line);
  background: var(--zl-surface);
}
.site-nav__menu[hidden] { display: none; }
.site-nav__menu a {
  padding-block: .7rem;
  border-bottom: 1px solid var(--zl-line);
  color: var(--zl-body);
  font-size: var(--zl-text-sm);
}
.site-nav__menu a:last-child { border-bottom: 0; }
.site-nav__menu a:hover { color: var(--zl-ink); }
.site-nav__menu-secondary { color: var(--zl-cobalt); }

/* The panel has no room for a hover menu, so Solutions flattens into a
   labelled pair instead of hiding its two destinations behind a toggle. */
.site-nav__menu-label {
  margin: 0;
  padding-block: .7rem .35rem;
  color: var(--zl-muted);
  font-size: var(--zl-text-xs);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.site-nav__menu-sub {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  padding-left: .85rem;
  border-left: 1px solid var(--zl-line);
}
.site-nav__menu-sub span {
  color: var(--zl-muted);
  font-size: var(--zl-text-xs);
}

/* Declared after the base .site-nav__toggle rule above -- an earlier media
   query would lose to it on source order alone. */
@media (max-width: 48rem) {
  .site-nav__toggle { display: inline-flex; }
}
@media (min-width: 48.0625rem) {
  .site-nav__menu { display: none; }
  .site-nav__toggle { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .site-nav__toggle-bars i { transition: none; }
}

/* Wide dropdown: the product line is two columns, so the panel is laid out
   as columns rather than one long list. Grid, not flex, so both columns
   share a baseline no matter how many entries each carries. */
/* The mega panel. Two lines side by side, and within Build the products are
   grouped People / Companies — a single seven-item column had become a list to
   read rather than a menu to scan [Arjun, 2026-08-06]. Anchored to the trigger
   rather than centred on the frame, so it never drifts away from what opened it. */
.site-nav__dropdown--wide {
  grid-template-columns: auto auto;
  gap: 0;
  min-width: 0;
  padding: 0;
}

.site-nav__mega { display: grid; grid-template-columns: repeat(2, 15rem); gap: clamp(1rem, 2.4vw, 2.25rem); }   /* widened: the Decision Makers tags were running up against the Companies column. Fixed rather than minmax(15rem, max-content) so the hover descriptions wrap inside the column instead of widening the panel -- both columns already measured exactly 15rem, so nothing moved. */
.site-nav__mega--single { grid-template-columns: 13.5rem; }

/* A line (Build / Grow) — its own bay in the panel */
.site-nav__bay { padding: 1rem; display: grid; gap: .75rem; align-content: start; }
.site-nav__bay + .site-nav__bay { border-left: 1px solid var(--zl-line); }

.site-nav__bay-head { display: grid; gap: .15rem; padding: 0 .75rem; }
.site-nav__bay-head b {
  color: var(--zl-ink);
  font-family: var(--zl-font-mono);
  font-size: var(--zl-text-xs);
  font-weight: var(--zl-weight-bold);
  letter-spacing: var(--zl-tracking-label);
  text-transform: uppercase;
}
.site-nav__bay-head span {
  color: var(--zl-muted);
  font-size: var(--zl-text-xs);
  white-space: nowrap;   /* a bay subtitle is one line at every width */
}

/* The overview sits under the groups it summarises, not among them. */
.site-nav__dropdown .site-nav__dropdown-title {
  display: flex;
  align-items: center;
  gap: .45rem;
  white-space: nowrap;
}

/* How a product is delivered, said once in the menu so the reader does not have
   to open a page to find out whether it is a call or a file [Arjun, 2026-08-07]. */
.site-nav__tag {
  flex: none;
  padding: .05rem .3rem;
  border: 1px solid var(--zl-line-strong);
  border-radius: 2px;
  color: var(--zl-muted);
  font-family: var(--zl-font-mono);
  font-size: .58rem;
  font-style: normal;
  font-weight: var(--zl-weight-regular);
  letter-spacing: var(--zl-tracking-label);
  text-transform: uppercase;
  line-height: 1.5;
}

.site-nav__dropdown-note { display: flex; align-items: center; gap: .45rem; }

/* ── The travelling focus frame ───────────────────────────────────────────
   Four corner brackets plus a faint wash. It began as a static mark on the one
   product a competitor cannot answer [Arjun, 2026-08-07], became a mark that
   travelled between the two differentiators, and is now the menu's hover
   indicator as well: it follows the pointer onto whatever card it is on, and
   falls back to the loop when the pointer leaves. The accent bar it replaces
   was deleted rather than kept alongside it — two marks arriving on the same
   card at the same moment said the same thing twice.

   Built in CSS plus ~90 lines of vanilla JS. The reference implementation is
   React and a motion library; this site has no build step and no runtime
   framework (house rule 4).

   ONE FRAME PER CARD, not one frame moved around the panel. Each is inset to
   its own link, so it is always exactly the right size for the card it marks,
   with nothing measured and nothing to re-measure when the menu reflows. Only
   the DIRECTION of each hop is computed in JS; every pixel of position here is
   the browser's own layout. A single moving frame would need the panel's
   geometry, every card's box, and a resize observer to stay honest.

   The offset a frame rests at while unlit is a pair of custom properties set
   on the LINK, so one declaration serves every direction — down, up, and
   sideways between the two columns.                                          */
.site-nav__focus {
  position: absolute;
  inset: -2px 0;
  pointer-events: none;
  opacity: 0;
  transform: translate(var(--zl-fx, 0px), var(--zl-fy, 16px)) scale(.97);
  /* The wash lives on the frame rather than on the link, so it fades with the
     corners on the same transition — nothing to keep in step by hand, and the
     link's own hover background is left alone. Kept low enough to read as a
     warming of the row rather than a highlight. */
  background: rgb(227 74 46 / .05);
  border-radius: 2px;
  transition:
    opacity var(--zl-nav-hop) var(--zl-ease-standard),
    transform var(--zl-nav-hop) var(--zl-ease-standard);
}
.site-nav__focus b {
  position: absolute;
  width: .42rem;
  height: .42rem;
  border: 1.5px solid var(--zl-vermilion);
  border-radius: 1px;
  filter: drop-shadow(0 0 3px rgb(227 74 46 / .45));
}
.site-nav__focus b:nth-child(1) { top: 0; left: 0;  border-right: 0; border-bottom: 0; }
.site-nav__focus b:nth-child(2) { top: 0; right: 0; border-left: 0;  border-bottom: 0; }
.site-nav__focus b:nth-child(3) { bottom: 0; left: 0;  border-right: 0; border-top: 0; }
.site-nav__focus b:nth-child(4) { bottom: 0; right: 0; border-left: 0;  border-top: 0; }

/* The lit card. JS sets --zl-fx/--zl-fy on the card being LEFT to point the way
   the frame is going, and on the card being ARRIVED at to point back the way it
   came, so the two halves of a hop read as one object crossing the gap. */
.site-nav__dropdown a.is-lit .site-nav__focus {
  opacity: 1;
  transform: translate(0, 0) scale(1);
}

/* The idle loop, for when nothing is hovered. Active Job Seekers holds the
   frame, it slides down and out while the Decision Makers frame slides in from
   above, holds there, and returns upward — two frames in strict antiphase, so
   exactly one is solid at any resting moment.

   Timing [Arjun, 2026-08-07]: four seconds parked on each row, with a slower
   and longer travel so the move between them is legible rather than a blink.

     0-42.5%    parked on Active Job Seekers   (4.0s)
     42.5-50%   travelling down                (0.7s)
     50-92.5%   parked on Decision Makers      (4.0s)
     92.5-100%  travelling back up             (0.7s)                        */
.site-nav__group:hover .is-focus--from .site-nav__focus,
.site-nav__group:focus-within .is-focus--from .site-nav__focus,
.site-nav__group[data-open="true"] .is-focus--from .site-nav__focus {
  animation: nav-focus-from 9.4s var(--zl-ease-standard) infinite;
}
.site-nav__group:hover .is-focus--to .site-nav__focus,
.site-nav__group:focus-within .is-focus--to .site-nav__focus,
.site-nav__group[data-open="true"] .is-focus--to .site-nav__focus {
  animation: nav-focus-to 9.4s var(--zl-ease-standard) infinite;
}

/* Only the Products bay runs an idle loop, because only it has two products
   worth pointing at. The Industries menu carries the frame and the typed
   description but no --from/--to pair, so it is still and waits for a pointer.
   site-nav.js handles an empty looper set: release() finds no home card, skips
   the walk back, and simply clears. */

/* Once the pointer takes over, the loop stops dead. A keyframe animation
   outranks a transition on the same property, so left running it would keep
   overwriting the frame the pointer is trying to drive. Four class-level
   selectors, so it outranks the [data-open] rules above without !important. */
.site-nav__group.is-tracking .is-focus .site-nav__focus { animation: none; }

@keyframes nav-focus-from {
  0%, 42.5% { opacity: 1; transform: translateY(0) scale(1); }
  50%       { opacity: 0; transform: translateY(16px) scale(.97); }   /* exits downward */
  92.5%     { opacity: 0; transform: translateY(16px) scale(.97); }
  100%      { opacity: 1; transform: translateY(0) scale(1); }        /* returns from below */
}
@keyframes nav-focus-to {
  0%, 42.5% { opacity: 0; transform: translateY(-16px) scale(.97); }  /* waits above */
  50%       { opacity: 1; transform: translateY(0) scale(1); }        /* arrives from the top */
  92.5%     { opacity: 1; transform: translateY(0) scale(1); }
  100%      { opacity: 0; transform: translateY(-16px) scale(.97); }  /* leaves upward */
}

@media (prefers-reduced-motion: reduce) {
  /* No loop and no travel. But the frame is the only hover indicator the menu
     has now, so it still has to appear — it cuts to the hovered card instead
     of crossing to it. */
  .site-nav__focus { transition: none; }
  .site-nav__group .is-focus .site-nav__focus {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
  /* The two resting marks stand down while the pointer drives: leaving them up
     would put three frames on screen at once. */
  .site-nav__group.is-tracking .is-focus .site-nav__focus { opacity: 0; }
  .site-nav__group .site-nav__dropdown a.is-lit .site-nav__focus {
    opacity: 1;
    transform: none;
  }
}

.site-nav__bay-foot {
  margin-top: .1rem;
  padding-top: .6rem;
  border-top: 1px solid var(--zl-line);
}

/* Stack only when the panel genuinely cannot fit. At 62rem it was collapsing
   to a 212px single column while the desktop nav was still showing — which is
   the long list the two-bay layout exists to avoid. */
@media (max-width: 52rem) {
  .site-nav__dropdown--wide { grid-template-columns: 1fr; min-width: 16rem; }
  .site-nav__mega { grid-template-columns: 1fr; gap: .75rem; }
  .site-nav__bay + .site-nav__bay { border-left: 0; border-top: 1px solid var(--zl-line); }
}

.site-nav__col { display: grid; gap: 2px; align-content: start; }

.site-nav__col-label {
  margin: 0 0 .35rem .75rem;
  color: var(--zl-muted);
  font-family: var(--zl-font-mono);
  font-size: var(--zl-text-xs);
  letter-spacing: var(--zl-tracking-label);
  text-transform: uppercase;
}
