@layer nav {
  .nav {
    position: sticky;
    top: 0;
    z-index: 100;
    background: oklch(100% 0 0 / 0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid oklch(0% 0 0 / 0.06);
    box-shadow: 0 1px 3px oklch(0% 0 0 / 0.03);
  }
  .nav-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 68px;
    height: auto;
  }
  .nav-links { display: flex; align-items: center; gap: var(--space-md); }

  /* Global unread-messages badge (injected by nav.js when signed in). */
  .nav-inbox-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: oklch(30% 0.02 276);
    padding: 6px;
    border-radius: 10px;
    transition: color .15s;
  }
  .nav-inbox-link:hover { color: var(--accent-solid); }
  /* Desktop bar is icon-only; the mobile panel reveals this (see system.css). */
  .nav-inbox-label { display: none; }
  .nav-inbox-link svg { transition: color .2s, transform 0.2s ease-out; }
  .nav-inbox-link:hover svg { transform: scale(1.08); }
  /* Kill the animated text-link underline on the icon link. Prefixed with .nav
     to out-specify the generic .nav-links a:not(.btn)::after (and its :hover). */
  .nav .nav-links a.nav-inbox-link::after,
  .nav .nav-links a.nav-inbox-link:hover::after { content: none; display: none; }
  .nav-inbox-badge {
    position: absolute;
    top: -2px;
    right: -2px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    box-sizing: border-box;
    border-radius: 999px;
    background: oklch(58% 0.21 27);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
  }
  .nav-links a:not(.btn),
  .nav-dash-row a:not(.btn-signout-burger):not(.btn),
  .nav-links > button {
    position: relative;
    font-size: 14px;
    font-weight: 500;
    color: oklch(40% 0.015 276);
    transition: color .2s;
    padding: 4px 0;
  }
  .nav-links a:not(.btn)::after,
  .nav-dash-row a:not(.btn-signout-burger):not(.btn)::after {
    content: '';
    position: absolute;
    bottom: -2px;
    left: 0;
    width: 0;
    height: 2px;
    background: oklch(53.6% 0.145 276);
    border-radius: 2px;
    transition: width .25s ease;
  }
  .nav-links a:not(.btn):hover::after,
  .nav-dash-row a:not(.btn-signout-burger):not(.btn):hover::after { width: 100%; }
  .nav-links a:not(.btn):visited,
  .nav-dash-row a:not(.btn-signout-burger):not(.btn):visited { color: oklch(40% 0.015 276); }
  .nav-links a:not(.btn):hover,
  .nav-links a:not(.btn):active,
  .nav-dash-row a:not(.btn-signout-burger):not(.btn):hover,
  .nav-dash-row a:not(.btn-signout-burger):not(.btn):active { color: oklch(53.6% 0.145 276); }
  .nav-links a.btn.btn-primary:visited,
  .nav-links .btn.btn-primary,
  .nav-links .btn.btn-outline,
  .nav-dash-row .btn.btn-primary {
    background: #292846 !important;
    color: #fff !important;
    border-color: #292846 !important;
  }
  .nav-links a.btn.btn-primary:visited:hover,
  .nav-links .btn.btn-primary:hover,
  .nav-links .btn.btn-outline:hover,
  .nav-links .btn.btn-primary:active,
  .nav-links .btn.btn-outline:active,
  .nav-dash-row .btn.btn-primary:hover {
    background: #56556f !important;
    color: #fff !important;
    border-color: #56556f !important;
    transform: none !important;
    box-shadow: none !important;
  }
  .nav-lang-btn {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 4px 8px;
    background: none;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: oklch(45% 0.01 276);
    transition: color .2s, background .2s;
  }
  .nav-lang-btn:hover { color: oklch(53.6% 0.145 276); background: oklch(90% 0.04 276 / 0.12); }
  .nav-lang-btn .lang-divider { color: oklch(80% 0.005 276); font-weight: 400; }
  .nav-lang-btn #langEn, .nav-lang-btn #langDa {
    padding: 1px 4px;
    border-radius: 3px;
    /* NB: opacity is intentionally NOT transitioned. The active/inactive state
       is set by JS (applyTranslations) on every page load. With an opacity
       transition, each load visibly animated the highlight from the default
       EN-active markup to DA over 200ms — the "flash of English" on the toggle.
       Snapping opacity makes the stored language appear instantly. */
    transition: background .2s, border-color .2s;
    border: 1.5px solid transparent;
  }
  .nav-lang-btn:not(.active) #langEn { color: oklch(50% 0.01 276); font-weight: 600; }
  .nav-lang-btn:not(.active) #langDa { opacity: 0.35; font-weight: 400; }
  .nav-lang-btn.active #langEn { opacity: 0.35; font-weight: 400; }
  .nav-lang-btn.active #langDa {
    font-weight: 600;
    color: oklch(50% 0.01 276);
  }
  .nav-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 14px;
    border-radius: 8px;
    background: transparent;
    transition: background .25s cubic-bezier(0.16, 1, 0.3, 1), padding .25s cubic-bezier(0.16, 1, 0.3, 1);
    flex-shrink: 1;
    min-width: 0;
  }
  .nav-search:hover { background: oklch(90% 0.004 276 / 0.4); }
  .nav-search:focus-within { background: oklch(96% 0.004 276); }
  .nav-search svg { width: 18px; height: 18px; color: oklch(50% 0.01 276); flex-shrink: 0; transition: color .2s, transform 0.2s ease-out; }
  .nav-search:hover svg { color: oklch(40% 0.015 276); }
  .nav-search input {
    border: none; outline: none; background: transparent;
    font-size: 13px; color: oklch(30% 0.015 276); width: 240px; min-width: 0;
  }
  .nav-search input::placeholder { color: oklch(65% 0.01 276); }
  .nav-separator { width: 1px; height: 24px; background: oklch(0% 0 0 / 0.08); flex-shrink: 0; }
  /* ── Burger toggle: "Menu" + a plus that spins into an × ──
     Ported from React Bits' <StaggeredMenu /> toggle. Two moving parts, both
     pure CSS: the label rolls vertically through alternating Menu/Close lines
     (js/staggered-menu.js builds the line stack and sets the transform), and
     the plus rotates 225° so its arms land as an ×. Sized in em against the
     button's own font so the icon tracks the label. ── */
  .nav-mobile-toggle {
    display: none;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    background: none; border: none;
    /* min-height, not just padding: a label + icon is only ~14px of content, so
       the button came out 30px tall inside a 69px bar — under the 44px touch
       target, and short enough that aiming at the word "Menu" on a phone
       regularly landed on .nav-inner instead and did nothing. The old hamburger
       was 40x40 and hid the problem. */
    min-height: 44px;
    padding: 8px 10px; cursor: pointer;
    color: oklch(30% 0.015 276);
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: -0.01em;
    line-height: 1;
    position: relative;
    border-radius: 10px;
    transition: background .2s ease, color .2s ease, transform .15s ease;
    /* Kill the browser's double-tap-to-zoom on this button: tapping it twice
       quickly (or spamming it open/closed) otherwise zooms the whole page in on
       the burger. 'manipulation' drops only the double-tap gesture — panning and
       PINCH ZOOM still work, so this is not the user-scalable=no accessibility
       trap. It also removes the ~300ms tap delay some engines add while they wait
       to see if a second tap is coming, so the menu reacts immediately. */
    touch-action: manipulation;
    -webkit-user-select: none;
    user-select: none;
  }
  .nav-mobile-toggle:hover {
    background: oklch(53.6% 0.145 276 / 0.08);
    color: oklch(53.6% 0.145 276);
  }
  .nav-mobile-toggle:active { transform: scale(0.92); }
  .nav-mobile-toggle.open {
    background: oklch(53.6% 0.145 276 / 0.1);
    color: oklch(53.6% 0.145 276);
  }
  /* The sheet's colour layers and page dim, injected into .nav by
     js/staggered-menu.js. Everything that positions them lives in the
     max-width:768px block in system.css, so hide them by default — otherwise
     two unstyled divs sit in the desktop bar's flow doing nothing. */
  .sm-prelayers, .sm-backdrop { display: none; }

  /* One-line window the label rolls through. --sm-toggle-width is measured in
     JS from the wider of the two words, so the icon beside it never shifts
     mid-roll; the em fallback covers the frame before that runs. */
  /* The label and the icon are decoration; the BUTTON is the control. Making
     them transparent to hit-testing is not cosmetic — it fixes a real bug.
     A tap used to land on the individual <span> holding the word "Menu", and
     the text roll rebuilds those spans from a MutationObserver microtask,
     which runs BETWEEN the button's own onclick and the document-level
     click-away handler in translations.js. That handler then saw a target
     detached from the DOM, decided `toggle.contains(target)` was false — i.e.
     that the tap had landed outside the button — and closed the menu the tap
     had just opened. Tapping the plus worked, because the icon's spans are
     never rebuilt. With pointer-events off, e.target is always the button,
     which nothing ever removes. */
  .sm-toggle-textWrap,
  .sm-icon { pointer-events: none; }

  .sm-toggle-textWrap {
    position: relative;
    display: block;
    height: 1em;
    overflow: hidden;
    white-space: nowrap;
    width: var(--sm-toggle-width, 3.4em);
  }
  .sm-toggle-textInner {
    display: flex;
    flex-direction: column;
    line-height: 1;
    transition: transform .4s cubic-bezier(0.16, 1, 0.3, 1);
  }
  .sm-toggle-line { display: block; height: 1em; line-height: 1; }
  .sm-icon {
    position: relative;
    width: 0.85em; height: 0.85em;
    flex: 0 0 0.85em;
    transition: transform .44s cubic-bezier(0.16, 1, 0.3, 1);
  }
  .sm-icon-line {
    position: absolute;
    left: 50%; top: 50%;
    width: 100%; height: 2px;
    background: currentColor;
    border-radius: 2px;
    transform: translate(-50%, -50%);
  }
  .sm-icon-line-v { transform: translate(-50%, -50%) rotate(90deg); }
  /* 225°, not 45° — the extra turn is what makes it read as a spin rather than
     a flip, and it lands on the same × either way. */
  .nav-mobile-toggle.open .sm-icon { transform: rotate(225deg); }
  @media (min-width: 769px) {
    .nav-dash-row > a:first-child {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 12px 24px;
      font-size: 15px;
      font-weight: 600;
      border-radius: 12px;
      background: #292846;
      color: #fff;
      border: 1.5px solid #292846;
      text-decoration: none;
      transition: background .2s, transform .2s;
    }
    .nav-dash-row > a:first-child:hover {
      background: #56556f;
      color: #fff;
      border-color: #56556f;
      transform: translateY(-1px);
    }
  }
  .nav-logo { color: #4d4d59; }
  .logo-text { font-family: var(--font-display); font-weight: 600; font-size: 20px; letter-spacing: -0.03em; color: #4d4d59; line-height: 1; }
  .logo-dk { font-size: 0.6em; font-weight: 400; color: #888; margin-left: 1px; }

  /* ── Nav search: collapsed icon on desktop/tablet, expands on click ──
     The container width stays AUTO the whole time and simply follows the input
     as its width animates open/closed — so there is never an auto↔fixed width
     jump (the old cause of the jerky, sudden close). One shared ease-in-out
     keeps both ends smooth. ── */
  @media (min-width: 769px) {
    .nav-links { --ns-ease: cubic-bezier(0.4, 0, 0.2, 1); }
    .nav-search {
      cursor: pointer;
      padding: 8px;
      height: 38px;
      gap: 0;
      box-sizing: border-box;
      border-radius: 10px;
      transition: gap 0.28s var(--ns-ease),
                  padding 0.28s var(--ns-ease),
                  background 0.24s ease,
                  box-shadow 0.28s var(--ns-ease);
    }
    .nav-search svg { transition: color 0.2s ease, transform 0.28s var(--ns-ease); }
    .nav-search:hover { background: oklch(96% 0 0); }
    .nav-search:hover svg { color: oklch(53.6% 0.145 276); transform: scale(1.08); }
    .nav-inbox-link svg { transition: color 0.2s ease, transform 0.28s var(--ns-ease); }
    .nav-inbox-link:hover svg { transform: scale(1.08); }
    .nav-search input {
      width: 0;
      padding: 0;
      opacity: 0;
      transition: width 0.28s var(--ns-ease),
                  opacity 0.16s ease;
    }
    .nav-search.expanded {
      gap: 8px;
      padding: 6px 14px;
      cursor: auto;
      background: oklch(100% 0 0);
      box-shadow: 0 0 0 1.5px oklch(53.6% 0.145 276 / 0.2), 0 4px 16px oklch(53.6% 0.145 276 / 0.1);
    }
    .nav-search.expanded:hover { background: oklch(100% 0 0); }
    .nav-search.expanded svg { color: oklch(53.6% 0.145 276); transform: scale(1.06); }
    .nav-search.expanded input {
      /* Grows leftward — everything to its right is fixed-width and the row is
         right-aligned — so this is bounded by the logo, not by the gap fix
         above. 320px still clears the logo at the 1025px breakpoint where the
         collapsed-icon layout starts. */
      width: 320px;
      opacity: 1;
      /* box widens first; the text fades in just behind it */
      transition: width 0.28s var(--ns-ease),
                  opacity 0.2s ease 0.07s;
    }
    /* "How it works" + "Services" fade/slide out as the search opens. Width is
       driven inline by JS (frozen px → 0) because CSS can't transition from an
       auto width; here we handle the fade + slide + spacing. */
    .nav-links a[data-i18n="nav.services"],
    .nav-links a[data-i18n="nav.howItWorks"] {
      white-space: nowrap;
      transition: width 0.28s var(--ns-ease),
                  opacity 0.2s ease,
                  transform 0.28s var(--ns-ease),
                  margin 0.28s var(--ns-ease),
                  padding 0.28s var(--ns-ease);
    }
    /* The divider collapses on the same curve as the two links it separates —
       once they are zero-width it has nothing on its right until the
       pre-login separator, and reads as a stray second bar.
       It is animated, NOT display:none. display flips instantly and does not
       transition, so on close the divider reappeared at frame 0 and shoved
       the still-full-width search box 25px sideways before the shrink even
       began — the box visibly jumped, then animated. */
    .nav-links .nav-search-divider {
      transition: width 0.28s var(--ns-ease),
                  opacity 0.2s ease,
                  margin 0.28s var(--ns-ease);
    }
    .nav-links.search-active a[data-i18n="nav.services"],
    .nav-links.search-active a[data-i18n="nav.howItWorks"] {
      opacity: 0;
      transform: translateX(-6px);
      margin: 0 !important;
      padding: 0 !important;
      pointer-events: none;
    }
    .nav-links.search-active .nav-search-divider {
      opacity: 0;
      width: 0;
    }
    /* Zero-width is not zero-space: a flex `gap` is reserved between every
       pair of adjacent children regardless of their size, so these three
       collapsed items still held 3 × var(--space-md) = 72px of dead air
       between the open search box and the separator. Each one pulls back the
       gap that precedes it, leaving a single normal gap. Keyed off the same
       token as `.nav-links`'s own `gap` so the two cannot drift apart. */
    .nav-links.search-active .nav-search-divider,
    .nav-links.search-active a[data-i18n="nav.services"],
    .nav-links.search-active a[data-i18n="nav.howItWorks"] {
      margin-inline-start: calc(-1 * var(--space-md)) !important;
    }

    /* ── Auto-hide the search icon while the page's own big header search
       bar is on screen ──
       Scoped with :has() to the two pages that actually ship one of those
       bars (the homepage hero, the Browse partners page band) -- everywhere
       else neither selector matches and .nav-search is untouched. Defaults
       to HIDDEN, not toggled hidden by JS: nav.js sits near the end of
       <body>, after nine other <script src> tags, so by the time it could
       run the icon would already have painted in its normal visible state --
       exactly the "browser paints X then visibly swaps it" flash this
       codebase has hit and fixed before (see the hero placeholder's inline
       pre-paint script). Starting hidden in CSS means nav.js only ever has
       to REVEAL it, never race to hide it.
       visibility (not just opacity) so the icon is untabbable while hidden --
       there is no reason a screen-reader or keyboard user should land on a
       second, invisible search box while the real one is right there on
       screen. The transition delays the visibility flip on the way OUT (so
       the fade is seen before the box leaves the a11y tree) but not on the
       way IN (so it's tabbable the instant it's visible again). */
    body:has(.hero-search) .nav-search,
    body:has(.hero-search) .nav-search-divider,
    body:has(.search-header-bar) .nav-search,
    body:has(.search-header-bar) .nav-search-divider {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transition: opacity .25s ease, visibility 0s linear .25s;
    }
    /* Same specificity as the rule above (body + one pseudo/class + one
       class); wins on source order alone, so it must stay textually after
       it. */
    body.nav-search-revealed .nav-search,
    body.nav-search-revealed .nav-search-divider {
      opacity: 1;
      visibility: visible;
      pointer-events: auto;
      transition: opacity .25s ease, visibility 0s linear 0s;
    }
  }
}
