/* ==========================================================================
   Spike site header — ported verbatim from the glossary
   (glossary/src/_includes/site-header.hbs + glossary/src/assets/css/glossary.css
    section 5 "Site header").

   The glossary concatenates this after brand/spike-theme.css, so the header
   rules below consume a handful of that file's tokens. Those tokens are
   resolved to their concrete spike-theme.css values in the :root shim here so
   this stylesheet is standalone and does not disturb the changelog's own
   Bootstrap-based styling. Everything else the header needs is already scoped
   to #site-header in the ported section.
   ========================================================================== */

/* ---- Self-hosted variable fonts (subset woff2, copied from the glossary) -- */
@font-face {
    font-family: 'Inter Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 400 600;
    src: url(/changelog/assets/fonts/inter-latin.woff2) format('woff2-variations');
}
@font-face {
    font-family: 'Instrument Sans Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 400 700;
    src: url(/changelog/assets/fonts/instrument-sans-latin.woff2) format('woff2-variations');
}
@font-face {
    font-family: 'Geist Mono Variable';
    font-style: normal;
    font-display: swap;
    font-weight: 400 500;
    src: url(/changelog/assets/fonts/geist-mono-latin.woff2) format('woff2-variations');
}

/* ---- spike-theme.css tokens the ported header section references ---------- */
:root {
    --spike-blue: #134ed9;
    --spike-black: #161618;
    --spike-white: #ffffff;

    --border: oklch(0.922 0 0); /* approx #e5e5e5 */

    --font-heading:
        'Instrument Sans Variable', system-ui, -apple-system, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;

    --container-max: 72rem;

    --ease-out: cubic-bezier(0, 0, 0.2, 1);
    --duration-hover: 120ms;
    --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-10: 2.5rem;

    /* Minimum interactive height — 48px on touch, 36px once there's a pointer
       (glossary.css section 2). */
    --tap: 3rem;
}
@media (pointer: fine) {
    :root {
        --tap: 2.25rem;
    }
}
.dark {
    --border: oklch(1 0 0 / 10%);
}

/* ---- Scoped reset — the glossary ships a global reset this header assumes;
   scoped to the header so it can't touch the rest of the changelog. --------- */
#site-header,
#site-header *,
#site-header *::before,
#site-header *::after {
    box-sizing: border-box;
}
#site-header ul,
#site-header ol {
    list-style: none;
    margin: 0;
    padding: 0;
}
#site-header li {
    margin: 0;
}
#site-header a {
    color: inherit;
    text-decoration: none;
}
#site-header button {
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
}
#site-header img,
#site-header svg {
    display: block;
    max-width: 100%;
}

/* ==========================================================================
   Ported verbatim from glossary/src/assets/css/glossary.css (section 5)
   ========================================================================== */
/* --------------------------------------------------------------------------
   5. Site header — modelled on website_astro-production's Header.astro
   (wordmark image, one independently-sized rounded dropdown panel per nav
   item — a wide Products panel with an integrations aside, a narrow Resources
   list — compacting shell, scroll-linked dark-hero flip). The transparent,
   scroll-away shell is a deliberate glossary-only departure so the header
   merges into the hero wash. See glossary.js for the matching behaviour.

   Its own local tokens are scoped to `#site-header` (not :root) because a few
   names — --font-sans, --font-mono, --text-sm/base, --radius-sm/md/lg —
   collide with brand/spike-theme.css; defining them globally would silently
   change type/radii sitewide. Scoping to the header keeps every descendant
   (including the dropdown panels and the fixed mobile sheet, which still
   inherit custom properties through the DOM regardless of position) resolving the
   header's own values without touching the rest of the page. `.btn` /
   `.btn-outline` are likewise addressed as `#site-header .btn…` because the
   bare class names are already used (with different styling) by the
   subscribe form and the "Contribute a term" link elsewhere on the page.
   -------------------------------------------------------------------------- */
@property --header-height {
    syntax: '<length>';
    inherits: true;
    initial-value: 72px;
}

/* Header geometry. The header is NOT pinned and does NOT compact on scroll —
   it scrolls away with the page like any other section. These are static:
   --float-gap / --bar-height shape the frosted pill's ::before box from lg up,
   --pill-width sets its (and the nav row's) width, and --header-height is the
   pill's full footprint = gap + bar, which .hero::before reads to run the hero
   wash up behind the header. On mobile the gap is 0 and the pill styling is
   off, so --header-height is just the flat bar height. */
:root {
    --float-gap: 0rem;
    --bar-height: 4.5rem;
    --pill-width: 60rem;
    --header-height: 4.5rem;
}

#site-header {
    --color-brand-primary: var(--spike-blue);
    --color-brand-black: var(--spike-black);

    --color-neutral-50: #f5f4f0;
    --color-neutral-100: var(--spike-white);
    --color-neutral-300: #bebcb4;
    --color-neutral-600: #6a6a63;
    --color-neutral-850: #28282a;

    --color-border-default: var(--border);
    --color-surface-subtle: #fcfbf9;
    --color-surface-2: #f4f3ef;
    --color-surface-icon: #777777;
    --color-neutral-400: #9a988f;

    --color-light-neutral-300: #c3c1c0;
    --color-dark-neutral-100: #717070;
    --color-dark-neutral-200: #5f5e5f;
    --color-dark-neutral-500: #313133;
    --color-dark-neutral-600: #28282a;

    --font-display: var(--font-heading);
    --font-sans: 'Inter Variable', ui-sans-serif, system-ui, sans-serif;
    --font-mono: 'Geist Mono Variable', ui-monospace, monospace;

    --text-sm: 0.8125rem;
    --text-base: 1rem;
    --tracking-mono: 0.06em;

    --radius-sm: 6px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-2xl: 20px;
    --radius-3xl: 24px;
}

/* ---- Layout / chrome ----------------------------------------------------- */
/* NOT pinned — the header scrolls away with the page. `position: relative`
   only so it stays a positioning context and its z-index keeps the dropdown
   panels above the content that follows. From lg up the visible chrome is a
   frosted, rounded, centred pill (::before, below); it just scrolls with
   everything else rather than staying stuck to the top. */
#site-header {
    position: relative;
    z-index: 50;
    height: var(--header-height);
    font-family: var(--font-sans);
}
@media (min-width: 64rem) {
    /* Pill sits 0.75rem down from the header's top edge and is 3.75rem tall,
       so the header box (gap + bar) is still 4.5rem — same as the mobile bar,
       so --header-height needs no breakpoint override. */
    :root {
        --float-gap: 0.75rem;
        --bar-height: 3.75rem;
    }
    /* The float gap is padding on the header (box-sizing: border-box keeps the
       total at --header-height), so the nav row and the pill ::before both
       start at the same 0.75rem offset and stay vertically locked. */
    #site-header {
        padding-top: var(--float-gap);
    }
}

/* Frosted-glass fill, painted on a pseudo-element (never on #site-header
   itself) so the nested backdrop-filters on the dropdown panels and the
   mobile sheet aren't trapped inside a backdrop root — see the long note in
   Header.astro. Below lg it's the full-bleed flat bar; from lg up it becomes
   the centred, fully-rounded pill with an all-around border, a soft float
   shadow and a 1px inner top-edge highlight. On the index the hero wash runs
   up behind it (see .hero::before) so the blur always has real content to
   sample. */
#site-header::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    /* Frosted glass, not solid — a light tint (never the dark one; header-dark
       is never toggled here, see spike-header.js) blurred over whatever
       scrolls underneath. */
    background-color: color-mix(in oklab, var(--color-neutral-100) 85%, transparent);
    backdrop-filter: blur(24px) saturate(170%);
    -webkit-backdrop-filter: blur(24px) saturate(170%);
    transition: background-color 200ms;
}
#site-header.header-dark::before {
    background-color: color-mix(in oklab, var(--color-brand-black) 70%, transparent);
}
@media (min-width: 64rem) {
    #site-header::before {
        inset: auto;
        top: var(--float-gap);
        left: 50%;
        transform: translateX(-50%);
        width: min(var(--pill-width), 100% - 2rem);
        height: var(--bar-height);
        border-radius: var(--radius-2xl);
        border: 1px solid var(--color-border-default);
        backdrop-filter: blur(28px) saturate(185%);
        -webkit-backdrop-filter: blur(28px) saturate(185%);
        box-shadow:
            var(--shadow-sm),
            inset 0 1px 0 0 color-mix(in oklab, var(--color-neutral-100) 55%, transparent);
        transition:
            background-color 200ms,
            border-color 200ms,
            box-shadow 200ms;
    }
    #site-header.header-dark::before {
        border-color: var(--color-dark-neutral-500);
        box-shadow:
            var(--shadow-sm),
            inset 0 1px 0 0 color-mix(in oklab, var(--color-neutral-100) 14%, transparent);
    }
}

/* First-paint guard. `.header-booting` is on <html> from the inline theme
   script and removed by glossary.js on the first frame, once the theme has
   been synced onto the header — so a dark-mode load lands with the pill
   already its dark tint instead of fading from light. */
.header-booting #site-header::before,
.header-booting #site-header::after,
.header-booting #site-header #site-logo {
    transition: none !important;
}

/* Bottom divider as an overlay (not a real border) so the header's box stays
   exactly the bar height. Full-bleed on the flat mobile bar; gone from lg up
   where the pill carries its own all-around border; suppressed in the dark
   treatment where it's a redundant seam over an identical background. */
#site-header::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    bottom: 0;
    height: 1px;
    background-color: var(--color-border-default);
    opacity: 1;
    pointer-events: none;
}
@media (min-width: 64rem) {
    #site-header::after {
        display: none;
    }
}
#site-header.header-dark::after {
    opacity: 0;
}

/* Below lg: the flat bar, centred to the content column. From lg up: centred
   to the pill width and a 3.75rem row that sits inside the frosted pill
   (::before). The row is pushed down by the float gap with padding on
   #site-header (see above) rather than a margin here — a top margin on this
   child collapses through the non-fixed header and desyncs it from the pill
   by exactly that gap. */
#site-header .site-nav {
    margin-inline: auto;
    max-width: var(--container-max);
    height: var(--header-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-inline: var(--space-4);
}
@media (min-width: 40rem) {
    #site-header .site-nav {
        padding-inline: var(--space-6);
    }
}
@media (min-width: 64rem) {
    #site-header .site-nav {
        width: min(var(--pill-width), 100% - 2rem);
        max-width: none;
        height: var(--bar-height);
    }
}

/* ---- Logo ----------------------------------------------------------------- */
#site-header .logo-link {
    position: relative;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* One wordmark asset serves both themes (no separate light/dark artwork
   exists yet) — it just stays put across the light/dark switch instead of
   cross-fading between a shown and a permanently-invisible twin. */
#site-logo {
    height: 1.5rem;
    width: auto;
}
/* Flattens the two-tone wordmark (dark text + blue spike) to solid white
   against the header's frosted-black chrome — cheaper than shipping a
   second logo asset. */
#site-header.header-dark #site-logo {
    filter: brightness(0) invert(1);
}

/* ---- Desktop nav ----------------------------------------------------------- */
#site-header .desktop-nav {
    display: none;
    align-items: center;
    gap: var(--space-6);
    list-style: none;
    margin: 0;
    padding: 0;
}
@media (min-width: 64rem) {
    #site-header .desktop-nav {
        display: flex;
    }
}
/* Every top-level item is a constant-height flex box (matching the pill's
   resting row height, like Header.astro's h-15) so the whole row is a hover
   target for its dropdown and the plain Pricing link shares the triggers'
   baseline. The pill compacts on a transform, so this stays fixed. */
#site-header .desktop-nav > li {
    display: flex;
    align-items: center;
    height: 3.75rem;
}

/* Each dropdown item is its own positioning context: unlike the old single
   full-width mega panel, every panel is now anchored to (and sized for) its
   own trigger. */
.nav-item {
    position: relative;
}

#site-header .nav-link-text {
    font-family: var(--font-mono);
    font-size: 0.875rem; /* 14px — the nav items hold their size; the rest of
                            the header chrome uses the smaller --text-sm */
    font-weight: 400;
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--color-dark-neutral-200);
    text-decoration: none;
    transition: color 200ms;
    background: none;
    border: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}
#site-header .nav-link-text:hover {
    color: var(--color-brand-black);
}
#site-header.header-dark .nav-link-text:hover {
    color: var(--color-light-neutral-300);
}

/* Keyboard-shortcut chips on LOG IN (L) and GET STARTED (S) — the bare-key
   handler lives in glossary.js's header(). Ported from Header.astro. Only
   meaningful with a real keyboard, so hidden on coarse pointers. */
#site-header .nav-kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1rem;
    padding: 0.125rem 0.375rem;
    /* Bootstrap ships `kbd { background-color: ... }` (a dark chip) on the
       bare element selector; the port never overrode it, so it silently won
       over this class's rule wherever the class lost the specificity tie. */
    background-color: transparent;
    border: 1px solid var(--color-border-default);
    border-radius: 3px;
    font-family: var(--font-mono);
    font-size: 0.625rem;
    line-height: 1;
    color: var(--color-neutral-600);
}
#site-header.header-dark .nav-kbd {
    border-color: var(--color-dark-neutral-500);
    color: var(--color-light-neutral-300);
}
#site-header .nav-kbd--on-brand {
    border-color: rgb(255 255 255 / 0.3);
    color: rgb(255 255 255 / 0.8);
}
#site-header.header-dark .nav-kbd--on-brand {
    border-color: rgb(255 255 255 / 0.3);
    color: rgb(255 255 255 / 0.8);
}
@media (pointer: coarse) {
    #site-header .nav-kbd {
        display: none;
    }
}
.nav-link-text .chevron {
    /* Without this, the compaction's real --pill-width shrink (a genuine
       layout resize, not just the visual scale() below it) forces the row
       narrower and the flex-shrinking SVG — the only child without an
       explicit basis, next to a nowrap text label that won't give up any
       width — absorbs the whole deficit and squashes down toward 0 wide.
       website_astro's original protects its chevrons the same way
       (Tailwind's `shrink-0`); the glossary's port never needed it because
       its header never compacted. */
    flex-shrink: 0;
    transition: transform 200ms;
}
.nav-item .nav-link-text[aria-expanded='true'] .chevron,
.nav-trigger:hover .chevron,
.nav-item:focus-within .nav-trigger .chevron {
    transform: rotate(-180deg);
}

/* ---- Dropdown panels ----------------------------------------------------- */
/* A small top padding on the wrapper (not a margin on the panel) bridges the
   gap between the trigger and the panel so the pointer can travel across it
   without :hover dropping. Anchored to the .nav-item, left-aligned to its
   trigger — the panel is only as wide as its own content needs. */
.nav-panel-wrap {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 40;
    padding-top: var(--space-3);
    visibility: hidden;
    pointer-events: none;
    transition: visibility 200ms;
}
.nav-item:hover .nav-panel-wrap,
.nav-item:focus-within .nav-panel-wrap {
    visibility: visible;
    pointer-events: auto;
}

.nav-panel {
    overflow: hidden;
    max-width: calc(100vw - 2rem);
    border-radius: var(--radius-2xl);
    border: 1px solid var(--color-border-default);
    opacity: 0;
    /* Drops down and settles from its trigger rather than just cross-fading,
       so the panel reads as belonging to the item above it. Kept tiny and
       fast — this is desktop hover, a frequent interaction. */
    transform: translateY(-6px) scale(0.985);
    transform-origin: top;
    background-color: color-mix(in oklab, var(--color-neutral-100) 92%, transparent);
    backdrop-filter: blur(32px) saturate(180%);
    -webkit-backdrop-filter: blur(32px) saturate(180%);
    transition:
        opacity 200ms var(--ease-out),
        transform 160ms var(--ease-out),
        background-color 200ms,
        border-color 200ms;
}
.nav-item:hover .nav-panel,
.nav-item:focus-within .nav-panel {
    opacity: 1;
    transform: none;
}
#site-header.header-dark .nav-panel {
    border-color: var(--color-dark-neutral-500);
    background-color: color-mix(in oklab, var(--color-brand-black) 90%, transparent);
}

.nav-panel--wide {
    width: 36rem;
}
.nav-panel--narrow {
    width: 15rem;
}
.nav-panel--wide .nav-panel-grid {
    display: grid;
    grid-template-columns: 1fr 1.05fr;
}

.nav-panel-list {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    list-style: none;
    margin: 0;
    padding: var(--space-3);
}
.nav-panel--narrow .nav-panel-list {
    padding: var(--space-2);
}

.nav-panel-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    border-radius: var(--radius-lg);
    padding: 0.625rem var(--space-3);
    text-decoration: none;
    transition: background-color 150ms;
}
.nav-panel-link:hover {
    background-color: var(--color-surface-subtle);
}
#site-header.header-dark .nav-panel-link:hover {
    background-color: var(--color-dark-neutral-600);
}

.nav-panel-icon {
    flex-shrink: 0;
    display: flex;
    height: 2rem;
    width: 2rem;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-default);
    background-color: var(--color-surface-subtle);
    color: var(--color-surface-icon);
}
.nav-panel-icon svg {
    width: 17px;
    height: 17px;
}
#site-header.header-dark .nav-panel-icon {
    border-color: var(--color-dark-neutral-500);
    background-color: var(--color-dark-neutral-600);
    color: var(--color-light-neutral-300);
}

.nav-panel-title {
    flex: 1;
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-neutral-850);
}
#site-header.header-dark .nav-panel-title {
    color: #ffffff;
}

/* Arrow slides in from the left on row hover / keyboard focus. */
.nav-panel-arrow {
    flex-shrink: 0;
    transform: translateX(-0.25rem);
    color: var(--color-neutral-400);
    opacity: 0;
    transition:
        transform 200ms,
        opacity 200ms;
}
.nav-panel-link:hover .nav-panel-arrow,
.nav-panel-link:focus-visible .nav-panel-arrow {
    transform: translateX(0);
    opacity: 1;
}
#site-header.header-dark .nav-panel-arrow {
    color: var(--color-light-neutral-300);
}

/* Products panel — right-hand "works with your stack" aside. Its tint reaches
   the panel's rounded corners because .nav-panel clips overflow. */
.nav-panel-aside {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: var(--space-5);
    padding: var(--space-6);
    background-color: var(--color-surface-2);
}
#site-header.header-dark .nav-panel-aside {
    background-color: var(--color-dark-neutral-600);
}
.nav-panel-aside-label {
    margin: 0;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 400;
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    color: var(--color-neutral-600);
}
#site-header.header-dark .nav-panel-aside-label {
    color: var(--color-dark-neutral-100);
}
.nav-panel-integrations {
    margin-top: var(--space-3);
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-2);
}
.nav-panel-integrations a {
    display: flex;
    aspect-ratio: 1 / 1;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border-default);
    background: #ffffff;
    padding: var(--space-2);
    transition: border-color 150ms;
}
.nav-panel-integrations a:hover {
    border-color: var(--color-neutral-300);
}
#site-header.header-dark .nav-panel-integrations a {
    border-color: var(--color-dark-neutral-500);
}
.nav-panel-integrations img {
    height: 2rem;
    width: 2rem;
    object-fit: contain;
}
.nav-panel-aside-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-brand-primary);
    text-decoration: none;
}
.nav-panel-aside-cta svg {
    transition: transform 200ms;
}
.nav-panel-aside-cta:hover svg {
    transform: translateX(2px);
}

/* ---- Customers panel — featured story card + short list ----------------- */
/* Centred under its trigger rather than left-aligned to it. */
.nav-panel-wrap--center {
    left: 50%;
    right: auto;
    transform: translateX(-50%);
}
.nav-panel-grid--customers {
    grid-template-columns: 1fr 1.1fr;
}
.nav-panel-col {
    display: flex;
    flex-direction: column;
    padding: var(--space-3);
}
.nav-panel-col-label {
    padding: var(--space-2) var(--space-3);
}
/* List rows here have no icon chip — just the name and the slide-in arrow. */
.nav-panel-link--plain {
    justify-content: space-between;
    gap: var(--space-6);
}
.nav-panel-col-cta {
    margin-top: var(--space-1);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    border-radius: var(--radius-lg);
    padding: 0.625rem var(--space-3);
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-brand-primary);
    text-decoration: none;
    transition: background-color 150ms;
}
.nav-panel-col-cta:hover {
    background-color: color-mix(in oklab, var(--color-brand-primary) 8%, transparent);
}
.nav-panel-col-cta svg {
    flex-shrink: 0;
    transition: transform 200ms;
}
.nav-panel-col-cta:hover svg {
    transform: translateX(2px);
}

.nav-panel-story {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    overflow: hidden;
    padding: var(--space-6);
    background: var(--color-brand-black);
    color: #ffffff;
    text-decoration: none;
}
.nav-panel-story-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.35;
    transition: transform 500ms;
}
.nav-panel-story:hover .nav-panel-story-bg {
    transform: scale(1.05);
}
.nav-panel-story-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(
        to top,
        var(--color-brand-black),
        color-mix(in oklab, var(--color-brand-black) 70%, transparent) 45%,
        transparent
    );
}
.nav-panel-story-body {
    position: relative;
}
.nav-panel-story-logo {
    height: 1.5rem;
    width: auto;
    max-width: 9rem;
    object-fit: contain;
    filter: brightness(0) invert(1);
}
.nav-panel-story-quote {
    display: block;
    margin-top: var(--space-4);
    font-family: var(--font-display);
    font-size: 1.125rem;
    line-height: 1.4;
    font-weight: 500;
    color: #ffffff;
}
.nav-panel-story-author {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin-top: var(--space-5);
}
.nav-panel-story-avatar {
    height: 2rem;
    width: 2rem;
    flex-shrink: 0;
    border-radius: 9999px;
    object-fit: cover;
    box-shadow: 0 0 0 1px rgb(255 255 255 / 0.2);
}
.nav-panel-story-meta {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.nav-panel-story-name {
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    font-weight: 500;
    color: #ffffff;
}
.nav-panel-story-role {
    font-family: var(--font-sans);
    font-size: 0.75rem;
    color: var(--color-light-neutral-300);
}
@media (prefers-reduced-motion: reduce) {
    .nav-panel-story:hover .nav-panel-story-bg {
        transform: none;
    }
    #site-header::before {
        transition: none;
    }
}

/* ---- Desktop right side: log in, theme toggle, CTA ------------------------ */
#site-header .desktop-actions {
    display: none;
    align-items: center;
    gap: var(--space-6);
}
@media (min-width: 64rem) {
    #site-header .desktop-actions {
        display: flex;
    }
}

#site-header .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    height: 2.75rem;
    border-radius: var(--radius-lg);
    padding-inline: var(--space-5);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-mono);
    font-weight: 400;
    text-decoration: none;
    white-space: nowrap;
    transition: all 150ms;
}
#site-header .btn-primary {
    color: #ffffff;
    background: #134ed9;
    /* No border — the generic `.btn` (shared with the subscribe form) adds a
       1px neutral one, which in light mode sits between the blue fill and the
       blue ring below and reads as a detached outline. The reference header
       (spike-header-standalone.html) carries the ring only. */
    border: 0;
    box-shadow:
        0 0 0 1px #1b56e1,
        0 1.5px 9px 0 rgba(22, 22, 24, 0.078),
        0 0.75px 1.5px -0.75px rgba(22, 22, 24, 0.078);
}
#site-header .btn-primary:hover {
    background: #0d379a;
}
#site-header .btn-outline {
    color: var(--color-brand-black);
    background: #ffffff;
    border: 1px solid #f0f0f0;
}
#site-header .btn-outline:hover {
    background: #f3f3f3;
}
#site-header .btn-outline-light {
    background: transparent;
    color: #ffffff;
    border: 1px solid rgba(255, 255, 255, 0.3);
}
#site-header .btn-outline-light:hover {
    background: #ffffff;
    color: var(--color-brand-black);
}
#site-header .btn-full {
    width: 100%;
}

/* Theme toggle — the site's existing dark/light switch (not part of the
   original mockup), dropped into the desktop and mobile action groups.
   Reuses the same sun/moon markup and `.dark` class contract used
   everywhere else on the page. The header itself paints no fill (see the
   comment above `#site-header .site-nav`), so a solid white background
   here read as a hardcoded white chip on any page whose background isn't
   the hero wash — e.g. flat #fcfbf9 on glossary item pages. Kept the
   bordered-chip affordance, but transparent-filled and colored off
   `--color-border-default` (same token the nav row's own border uses) so
   the ring reads correctly against whatever's behind the header. In
   `header-dark`, it keeps using the same `--border` token rather than a
   one-off white value — `--border` already resolves to white @ 10% under
   the site's `.dark` theme (see brand/spike-theme.css), which is what
   every other bordered surface on the page uses. */
.theme-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: var(--tap);
    height: var(--tap);
    padding: 0;
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-md);
    background: none;
    color: var(--color-brand-black);
    cursor: pointer;
    transition:
        color var(--duration-hover) var(--ease-out),
        border-color var(--duration-hover) var(--ease-out);
}
#site-header.header-dark .theme-toggle {
    color: #ffffff;
    border-color: var(--border);
}
.js .theme-toggle {
    display: inline-flex;
}
@media (min-width: 64rem) {
    /* A compact square in the pill — smaller than the CTA next to it;
       align-items:center on .site-nav keeps the three flush. */
    #site-header .desktop-actions .theme-toggle {
        width: 1.9rem;
        height: 1.9rem;
    }
}
.theme-toggle:hover {
    color: var(--color-dark-neutral-100);
}
#site-header.header-dark .theme-toggle:hover {
    color: var(--color-light-neutral-300);
}
.theme-toggle svg {
    width: 1rem;
    height: 1rem;
}
/* The button shows the current *preference* (monitor / sun / moon), not the
   resolved theme — so "System" reads as system even when the OS is dark.
   Driven by data-theme-pref on <html> (set pre-paint by the inline script). */
.theme-toggle .icon-system,
.theme-toggle .icon-sun,
.theme-toggle .icon-moon {
    display: none;
}
:root:not([data-theme-pref]) .theme-toggle .icon-system,
:root[data-theme-pref='system'] .theme-toggle .icon-system,
:root[data-theme-pref='light'] .theme-toggle .icon-sun,
:root[data-theme-pref='dark'] .theme-toggle .icon-moon {
    display: block;
}
/* ---- Mobile toggle ---------------------------------------------------- */
/* Groups the theme toggle and the hamburger so .site-nav's
   justify-content:space-between treats them as one cluster pinned to the
   right, instead of spreading two separate flex children across the row. */
.mobile-header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
@media (min-width: 64rem) {
    /* The desktop-actions copy (#theme-toggle) takes over from here. Hiding
       just the two children left this wrapper as a zero-width flex item —
       .site-nav's justify-content:space-between still reserved a gap for
       it, pushing .desktop-actions ~79px short of the row's right edge
       instead of flush with the page content below. */
    .mobile-header-actions {
        display: none;
    }
    #theme-toggle-mobile {
        display: none;
    }
}
.mobile-menu-toggle {
    position: relative;
    display: inline-flex;
    height: 2.5rem;
    width: 2.5rem;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    color: var(--color-brand-black);
    background: none;
    border: none;
    cursor: pointer;
}
@media (min-width: 64rem) {
    .mobile-menu-toggle {
        display: none;
    }
}
.mobile-menu-toggle.is-dark {
    color: #ffffff;
}
.mobile-menu-toggle svg {
    position: absolute;
    transition: all 300ms;
}
#mobile-menu-icon-close {
    transform: rotate(-90deg) scale(0.75);
    opacity: 0;
}
#mobile-menu-icon-open.is-open {
    transform: rotate(90deg) scale(0.75);
    opacity: 0;
}
#mobile-menu-icon-close.is-open {
    transform: none;
    opacity: 1;
}

/* ---- Mobile sheet ------------------------------------------------------ */
#mobile-menu {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    top: var(--header-height);
    z-index: 30;
    overflow-y: auto;
    visibility: hidden;
    opacity: 0;
    border-top: 1px solid var(--color-border-default);
    background-color: color-mix(in oklab, var(--color-neutral-100) 92%, transparent);
    backdrop-filter: blur(32px) saturate(180%);
    -webkit-backdrop-filter: blur(32px) saturate(180%);
    transition:
        opacity 300ms,
        visibility 300ms;
}
@media (min-width: 64rem) {
    #mobile-menu {
        display: none;
    }
}
#mobile-menu.is-open {
    visibility: visible;
    opacity: 1;
}
#site-header.header-dark #mobile-menu {
    border-color: var(--color-dark-neutral-500);
    background-color: color-mix(in oklab, var(--color-brand-black) 90%, transparent);
}
.mobile-menu-inner {
    margin-inline: auto;
    max-width: var(--container-max);
    min-height: 100%;
    display: flex;
    flex-direction: column;
    padding: var(--space-10) var(--space-6) var(--space-8);
}
@media (min-width: 40rem) {
    .mobile-menu-inner {
        padding-inline: var(--space-8);
    }
}
.mobile-nav-list {
    flex: 1;
    list-style: none;
    margin: 0;
    padding: 0;
}
.mobile-nav-item {
    border-bottom: 1px solid var(--color-border-default);
}
#site-header.header-dark .mobile-nav-item {
    border-color: var(--color-dark-neutral-500);
}
/* Prefixed with #site-header (not just .mobile-nav-trigger) so this beats
   `#site-header button { font: inherit }` above on specificity — a bare
   class selector loses to that ID-scoped reset and silently fell back to
   the page's sans body font at 16px instead of the intended mono/13px. */
#site-header .mobile-nav-trigger {
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: space-between;
    padding-block: var(--space-5);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    color: var(--color-brand-black);
    background: none;
    border: none;
    cursor: pointer;
}
#site-header.header-dark .mobile-nav-trigger {
    color: #ffffff;
}
.mobile-nav-trigger .chevron {
    transition: transform 300ms;
    flex-shrink: 0;
}
.mobile-nav-trigger[aria-expanded='true'] .chevron {
    transform: rotate(90deg);
}
.mobile-nav-link {
    display: block;
    padding-block: var(--space-5);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    letter-spacing: var(--tracking-mono);
    text-transform: uppercase;
    color: var(--color-brand-black);
    text-decoration: none;
}
#site-header.header-dark .mobile-nav-link {
    color: #ffffff;
}
.mobile-panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 300ms;
}
.mobile-panel.is-open {
    grid-template-rows: 1fr;
}
.mobile-panel-scroll {
    overflow: hidden;
}
.mobile-link-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-bottom: var(--space-4);
    list-style: none;
    margin: 0;
    padding-left: 0;
}
.mobile-link-item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    padding: 0.625rem var(--space-2);
    text-decoration: none;
    transition: all 150ms;
}
.mobile-link-item:hover {
    border-color: var(--color-border-default);
    background-color: var(--color-surface-subtle);
}
.mobile-link-icon {
    flex-shrink: 0;
    display: flex;
    height: 2.125rem;
    width: 2.125rem;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-default);
    background-color: var(--color-surface-subtle);
    color: var(--color-surface-icon);
}
.mobile-link-title {
    font-family: var(--font-sans);
    font-size: var(--text-sm);
    color: var(--color-neutral-850);
}
#site-header.header-dark .mobile-link-title {
    color: #ffffff;
}
.mobile-actions {
    margin-top: var(--space-8);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.hidden-important {
    display: none !important;
}

@media (prefers-reduced-motion: reduce) {
    #site-header * {
        transition: none !important;
    }
}

/* ==========================================================================
   Scroll-linked compaction
   Ported from website_astro-production/src/components/Header.astro.

   The glossary header scrolls away with the page. This pins it (fixed, from
   lg up) with a constant-height spacer so scrolling stays 1:1 with the wheel,
   and eases it down to a shorter, narrower pill once you scroll past ~56px.

   --header-progress is only ever flipped 0<->1 by spike-header.js; the 360ms
   transition on it (a registered @property) is the whole trick — it spreads
   the compaction of every derived value over one shared, time-based clock, so
   a hard downward flick morphs smoothly instead of snapping 0->1 in one frame.
   ========================================================================== */
@property --header-progress {
    syntax: '<number>';
    inherits: true;
    initial-value: 0;
}

:root {
    --header-progress: 0;
}

/* Below lg the header is still the in-flow glossary bar, so the spacer takes
   up no room; the lg block below flips it on. Declared first so the media
   query wins on source order (neither adds specificity). */
#site-header-spacer {
    display: none;
}

@media (min-width: 64rem) {
    :root {
        /* Resting pill 3.75rem (60px) -> 3.25rem (52px) as it compacts;
           60rem wide -> 50rem. Overrides the static glossary values above. */
        --bar-height: calc(3.75rem - 0.5rem * var(--header-progress));
        --pill-width: calc(60rem - 10rem * var(--header-progress));
        --header-height: calc(var(--float-gap) + var(--bar-height));
        transition: --header-progress 360ms cubic-bezier(0.33, 1, 0.68, 1);
    }

    /* Pin it. The glossary rule is `position: relative` (scrolls away); fixed
       + the constant-height spacer decouples the compaction from document
       flow, so the page never travels further than the wheel asked for. */
    #site-header {
        position: fixed;
        inset-inline: 0;
        top: 0;
    }

    /* Constant stand-in for the header now taken out of flow. Never shrinks —
       that constant is what keeps the scroll 1:1 while the bar compacts over
       the top of content that isn't moving. */
    #site-header-spacer {
        display: block;
        height: 4.5rem;
    }

    /* Logo, nav labels and the actions cluster scale down on `transform`
       only, so nothing here reflows on scroll — it all composites on one
       layer. NOTE this is a deliberate departure from website_astro's
       Header.astro: there the nav row keeps a CONSTANT height and overhangs
       the shrinking pill, so its version also needs a manual translateY to
       re-centre the overhanging content. Here `#site-header .site-nav`'s own
       height is already tied to `--bar-height` (see above), so the row
       shrinks in lockstep with the pill and flexbox's `align-items: center`
       re-centres everything for free — adding that same translateY on top
       double-corrects and pushes the content off-centre. Scale only. */
    #site-header #site-logo {
        transform: scale(calc(1 - 0.167 * var(--header-progress)));
        transform-origin: left center;
        will-change: transform;
    }

    #site-header .nav-link-text {
        transform: scale(calc(1 - 0.143 * var(--header-progress)));
        transform-origin: center;
        will-change: transform;
    }

    /* LOG IN + GET STARTED scale as one unit toward their shared right edge so
       they stay locked together as the pill compacts; the login link opts out
       of the per-.nav-link-text transform just below so it isn't scaled twice. */
    #site-header .desktop-actions {
        transform: scale(calc(1 - 0.14 * var(--header-progress)));
        transform-origin: right center;
        will-change: transform;
    }
    #site-header .desktop-actions .nav-link-text {
        transform: none;
    }
}

/* No eased compaction under reduced motion — the pill snaps between its two
   states instead of morphing. */
@media (prefers-reduced-motion: reduce) {
    :root {
        transition: none;
    }
}
