/* ============================================================
   causl.org shared header.
   Same element on every page. On the home page it starts as the
   full hero (logo + pronunciation + tagline) and shrinks into a
   sticky bar as the user scrolls — the .is-hero class plus three
   scroll-driven CSS variables (--p1, --p2, --p3) drive the
   transition. Inner pages omit .is-hero (and pin the variables
   to 1) so they begin in the collapsed bar shape.

   The burger button on the right opens a drawer that holds every
   nav link plus the light/dark mode toggle.

   HISTORY:
     - Originally a verbatim port of libviprs-org/topbar.css (#1272).
     - #1289 removed the discrete `.collapsed` class flip (which
       used to toggle `position: fixed` and a `body:has(...)
       padding-top` reservation) because the up/down boundary at the
       collapse threshold produced a scroll-flicker loop (see the
       #1277 diagnostic trace). The bar now stays `position: sticky`
       at every scroll position and only the `--p1/--p2/--p3`
       custom properties change. JS quantizes the scrollY → p
       mapping into 5 discrete steps so each scroll event either
       leaves the layout untouched or moves it through a single
       deterministic transition — never up *and* down across the
       same threshold on consecutive frames.

   The causl-specific patches on top of the libviprs port:
     1. Colour values → causl pair-tokens
          background  →  var(--surface-overlay) family
          text colour →  var(--text-on-overlay)
          current pill →  var(--surface-emphasis)/--text-on-emphasis
     2. Font family   →  var(--sans)
     3. Brand mark img selector targets <img class="topbar-brand-img">
          (causl HTML keeps the class for selector specificity, but
          .topbar-brand img is functionally identical, and the
          two-class wrapper continues to point at img/causl-mark.svg
          per the brand spec §11 — one plate-less mark on every theme.)
   ============================================================ */

:root {
  --topbar-zindex: 1100;
}

.topbar {
  /* Defaults are the *collapsed* values — inner pages render that
     way without any JS. .is-hero overrides them to start at 0 and
     JS interpolates them back toward 1 on scroll. */
  --p1: 1;  /* fades pronunciation/tagline/badges */
  --p2: 1;  /* shrinks logo + brand name */
  --p3: 1;  /* shrinks padding */

  /* Fixed at the viewport top regardless of scroll position. Taking
     the bar OUT OF FLOW (vs the previous sticky-in-flow approach) is
     what eliminates the #1289 scroll-flicker: when the bar's height
     animated between hero and collapsed states while sitting IN flow,
     each height change reshuffled the document below by tens of pixels.
     Browser scroll-anchoring then re-pinned scrollY, pushing the page
     across the collapse threshold, which retriggered the height
     animation — an infinite loop visible in the #1277 trace.
     With position: fixed, height changes affect only the bar itself;
     document flow is unchanged; scrollY stays put; no loop.
     body { padding-top: var(--topbar-max-height) } below reserves the
     fixed-bar's max footprint so content never sits behind it. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--topbar-zindex);
  background: var(--surface-overlay);
  color: var(--text-on-overlay);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  /* The calc() values below are tuned for the scroll-collapse
     animation (#1272); leave the literals alone so the curve
     stays bit-identical to libviprs-org/topbar.css. */
  padding: calc(0.5rem + 2.5rem * (1 - var(--p3))) 1.25rem
           calc(0.5rem + 2rem * (1 - var(--p3)));
  font-family: var(--sans);
  text-align: center;
  /* Top-level flex container. Bar stays in column layout at every
     scroll position; the hero content (pronunciation/tagline/badges)
     fades to opacity:0 + max-height:0 + overflow:hidden via --p1, so
     the visible "collapsed" state is just brand + nav stacked tightly
     under the small padding driven by --p3. */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
}

/* Kill horizontal overflow at the document root so a stray wide
   element (long code block, wide table, oversized image) can't
   force the page wider than the viewport on mobile. `clip` is used
   instead of `hidden` because `clip` doesn't create a new scrolling
   container; the fixed topbar still composites correctly above it. */
html, body {
  overflow-x: clip;
  max-width: 100%;
}

/* Reserve the topbar's max footprint so content under the fixed bar
   never gets hidden. `--topbar-max-height` is measured + written by
   js/topbar.js at init time (and re-measured on resize); the literal
   fallback below covers the no-JS path with the rough hero-state height
   so server-rendered HTML still reads correctly before scripts settle.
   Inner pages (no .is-hero) measure to the collapsed height (smaller),
   so the gap below the bar is tight; the homepage measures the full
   hero stack (taller). */
body {
  padding-top: var(--topbar-max-height, 280px);
}

.topbar.is-hero {
  --p1: 0;
  --p2: 0;
  --p3: 0;
}

/* .topbar-content stacks brand + hero block + nav vertically at
   every scroll position, centred horizontally. The hero block
   (pronunciation/tagline/badges) collapses to zero height via --p1,
   the brand mark + name shrink via --p2, and the outer padding
   tightens via --p3 — three independent dials, no class flip. */
.topbar-content {
  max-width: var(--max-width, 1100px);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

/* Brand: logo + project name. Always links to the site root.
   margin-bottom is driven by --p2 directly: 1rem in hero (p2=0) →
   0 in collapsed (p2=1), so no class-flip rule is needed. */
.topbar-brand {
  display: inline-flex;
  align-items: center;
  /* calc() driven by --p2 (scroll-collapse curve, #1272); keep
     literals untouched — they're tuned against libviprs-org. */
  gap: calc(0.55rem + 0.7rem * (1 - var(--p2)));
  margin-bottom: calc(1rem * (1 - var(--p2)));
  text-decoration: none;
  color: var(--text-on-overlay);
  flex-shrink: 0;
}

/* Brand mark: <img src="img/causl-mark.svg"> — plate-less per the
   brand spec §11 so the same asset works on both themes. The
   drop-shadow opacity is driven off --p2 so the shadow fades out as
   the mark shrinks — replaces the old `.collapsed { filter: none }`
   flip. */
.topbar-brand img,
.topbar-brand .topbar-brand-img {
  width: calc(28px + 52px * (1 - var(--p2)));
  height: auto;
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, calc(0.3 * (1 - var(--p2)))));
  transition: filter 0.2s;
}

.topbar-brand .brand-name {
  font-size: calc(1.1rem + 1.7rem * (1 - var(--p2)));
  font-weight: 700;
  letter-spacing: -0.5px;
  line-height: 1.1;
  white-space: nowrap;
}

.topbar-brand .brand-sub {
  font-size: 0.85rem;
  font-weight: 400;
  opacity: 0.7;
  margin-left: var(--space-2);
}

/* Causl-only: the trailing "l" in `caus<span class="accent">l</span>`
   is brand-accented so the wordmark reads "caus·l" with a colour
   shift on the last glyph. */
.topbar-brand .brand-name .accent {
  color: var(--surface-emphasis);
}

/* Hero-only content: pronunciation + tagline + badges. They fade
   away (opacity + max-height + margin) under --p1 control. At p1=1
   opacity is 0, max-height is 0, margin is 0 and overflow:hidden
   clips any leftover content — so they take no visible space on
   inner pages or on the home page once fully scrolled. The previous
   `.topbar.collapsed { display: none }` flip is gone, since it
   contributed to the #1289 layout-shift flicker. */
.topbar .pronunciation,
.topbar .tagline,
.topbar .badges {
  opacity: calc(1 - var(--p1));
  overflow: hidden;
}

.topbar .pronunciation {
  /* IPA glyphs (e.g. /ˈkɔː.zəl/) aren't in var(--sans)'s default
     coverage on most systems; SIL fonts ship with the full IPA
     block and diacritics, DejaVu Sans is a Linux fallback. */
  font-family: "Charis SIL", "Doulos SIL", "Gentium Plus",
               "DejaVu Sans", "Lucida Sans Unicode", serif;
  font-size: 0.95rem;
  color: var(--text-on-overlay);
  font-style: italic;
  max-height: calc((1 - var(--p1)) * 3rem);
  margin-bottom: calc((1 - var(--p1)) * 0.75rem);
  letter-spacing: 0.5px;
}

.topbar .tagline {
  font-size: 1.15rem;
  color: var(--text-on-overlay);
  max-width: 600px;
  max-height: calc((1 - var(--p1)) * 5rem);
  margin: 0 auto calc((1 - var(--p1)) * 1.5rem);
}

.topbar .badges {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
  flex-wrap: wrap;
  max-height: calc((1 - var(--p1)) * 3rem);
  margin-bottom: calc((1 - var(--p1)) * 1.5rem);
}

.topbar .badges img { height: 20px; }

/* Burger toggle — absolutely positioned in the top-right of the bar
   at every scroll position. (The previous `.topbar.collapsed` rule
   that flipped it to `position: static` in a flex row was removed
   with the rest of the collapse-flip — keeping it absolute in every
   state means the burger sits in the same on-screen spot regardless
   of scroll, which is what users have effectively been seeing once
   the JS settles past the threshold.) Sized and offset directly off
   --p2 so it shrinks slightly along with the brand. */
.topbar-burger {
  position: absolute;
  top: calc(0.45rem + 0.4rem * (1 - var(--p2)));
  right: calc(0.5rem + 0.35rem * (1 - var(--p2)));
  width: calc(2rem + 0.4rem * (1 - var(--p2)));
  height: calc(2rem + 0.4rem * (1 - var(--p2)));
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: var(--text-on-overlay);
  border-radius: 6px;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s, top 0.2s, right 0.2s, width 0.2s, height 0.2s;
  z-index: calc(var(--topbar-zindex) + 1);
}

.topbar-burger:hover { background: var(--state-hover-bg); }

.topbar-burger .burger-icon,
.topbar-burger .burger-icon::before,
.topbar-burger .burger-icon::after {
  display: block;
  width: 1.2rem;
  height: 2px;
  background: var(--text-on-overlay);
  border-radius: 1px;
  transition: transform 0.25s ease, top 0.25s ease, opacity 0.2s ease, background 0.2s ease;
}

.topbar-burger .burger-icon { position: relative; }
.topbar-burger .burger-icon::before { content: ''; position: absolute; left: 0; top: -7px; }
.topbar-burger .burger-icon::after  { content: ''; position: absolute; left: 0; top:  7px; }

.topbar.menu-open .topbar-burger .burger-icon { background: transparent; }
.topbar.menu-open .topbar-burger .burger-icon::before { top: 0; transform: rotate(45deg); }
.topbar.menu-open .topbar-burger .burger-icon::after  { top: 0; transform: rotate(-45deg); }

/* Drawer — overlays page content via position: absolute below the
   bar. Hidden by default; .menu-open on the bar reveals it. */
.topbar-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface-overlay);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.3);
  padding: var(--space-2);
  z-index: var(--topbar-zindex);
  text-align: left;
}

.topbar.menu-open .topbar-menu { display: block; }

.topbar-menu-inner {
  max-width: var(--max-width, 1100px);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  /* 0.15rem — sub-grid hairline gap between drawer items; keep literal. */
  gap: 0.15rem;
}

.topbar-menu a,
.topbar-menu .topbar-theme-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3);
  color: var(--text-on-overlay);
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 600;
  background: transparent;
  border: none;
  border-radius: 4px;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s;
  box-sizing: border-box;
}

.topbar-menu a:hover,
.topbar-menu .topbar-theme-toggle:hover {
  background: var(--state-hover-bg);
}

.topbar-menu a.is-current { background: rgba(255, 255, 255, 0.18); }

.topbar-menu .menu-divider {
  height: 1px;
  margin: var(--space-1) var(--space-2);
  background: rgba(255, 255, 255, 0.15);
  border: none;
}

.topbar-theme-toggle .theme-glyph {
  display: inline-block;
  width: 1.1rem;
  text-align: center;
}

@media (max-width: 600px) {
  .topbar-burger { width: 2.1rem; height: 2.1rem; top: var(--space-2); right: var(--space-2); }
  .topbar-brand .brand-sub { display: none; }
  /* Tighten the hero on phones so the burger doesn't feel cramped. */
  .topbar.is-hero .topbar-brand img,
  .topbar.is-hero .topbar-brand .topbar-brand-img {
    width: calc(28px + 28px * (1 - var(--p2)));   /* 28 → 56 */
  }
  .topbar.is-hero .topbar-brand .brand-name {
    font-size: calc(1rem + 1rem * (1 - var(--p2)));  /* 1 → 2rem */
  }
}

/* Phone-sized collapse: tighter horizontal padding once the bar is
   shrunk, so the brand and burger don't feel cramped. Driven off
   --p3 instead of a class flip — at p3=1 (collapsed/inner pages)
   horizontal padding lands at 0.65rem; at p3=0 (hero) it lands at
   the desktop default 1.25rem. */
@media (max-width: 700px) {
  .topbar {
    padding: calc(0.45rem + 2.55rem * (1 - var(--p3)))
             calc(0.65rem + 0.6rem * (1 - var(--p3)))
             calc(0.45rem + 2.05rem * (1 - var(--p3)));
  }
}

/* ============================================================
   Desktop overrides (≥ 701 px).
   No burger menu — nav items list inline in the hero, then
   horizontally across the bar when collapsed.
   ============================================================ */
@media (min-width: 701px) {
  .topbar-burger { display: none; }

  /* Drawer becomes an inline strip; no overlay positioning. */
  .topbar-menu {
    display: block;
    position: static;
    background: transparent;
    border-top: none;
    box-shadow: none;
    padding: 0;
  }

  .topbar-menu-inner {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-2);
  }

  /* Inline nav items styled as outline buttons. */
  .topbar-menu a,
  .topbar-menu .topbar-theme-toggle {
    width: auto;
    padding: var(--space-2) var(--space-4);
    font-size: 0.85rem;
    font-weight: 600;
    background: transparent;
    border: 1.5px solid rgba(255, 255, 255, 0.4);
    border-radius: 4px;
    line-height: 1.2;
    transition: opacity 0.2s, background 0.2s, border-color 0.2s;
  }

  .topbar-menu a:hover,
  .topbar-menu .topbar-theme-toggle:hover {
    opacity: 0.9;
    background: var(--state-hover-bg);
    border-color: rgba(255, 255, 255, 0.6);
  }

  /* Highlight the current page with the paired emphasis surface. */
  .topbar-menu a.is-current {
    background: var(--surface-emphasis);
    border-color: var(--surface-emphasis);
    color: var(--text-on-emphasis);
  }

  .topbar-menu a.is-current:hover {
    opacity: 0.9;
    background: var(--surface-emphasis);
    color: var(--text-on-emphasis);
  }

  /* The mobile-only divider has no purpose in the inline strip. */
  .topbar-menu .menu-divider { display: none; }

  /* Nav strip sits in flow below the brand in every state. Margin is
     driven off --p1 so it tightens up slightly as the bar collapses,
     without a discrete class flip. Previously (before #1289) this
     also right-aligned the nav in collapsed state via a flex-row
     flip on the bar; the row-flip was removed to eliminate the
     scroll-flicker boundary, so the inline strip now stays centred
     in every state. */
  .topbar .topbar-menu {
    margin-top: calc(0.5rem * (1 - var(--p1)));
    padding-bottom: calc(0.5rem * (1 - var(--p1)));
  }
}
