/* The vector ascent — the page's opening climb.
   Transplanted from Peak's own "Peak" site template. Two things differ from
   the standalone version, both forced by living inside a longer page:

   - The world is `sticky` inside this section rather than `fixed` to the
     viewport, so it releases the moment the climb is over and the rest of the
     page scrolls normally over it.
   - Progress is measured across this section's height, not the document's.

   Everything is namespaced under #ascent-vector because the template's own
   class names (.lede, .button) already mean something else in site.css. */

#ascent-vector {
  --p: 0;              /* section progress, written by ascent.js */
  --travel: 1;         /* parallax distance multiplier; reduced on tall screens */

  --av-ink: #F0EEE6;
  --av-accent: var(--clay);

  --sky-top: #8ba3b4;
  --sky-bottom: #cdc0ad;
  --haze: #cdc0ad;
  --rock-far: #8297a7;
  --rock-mid: #62798a;
  --rock-near: #455a6a;
  --rock-trees: #2d3e48;
  --rock-fore: #1a262d;

  position: relative;
  color: var(--av-ink);

  /* site.css gives every <section> 128px of vertical padding. This one is the
     full-bleed opening of the page, so that padding is a black band above the
     sky and another below the summit. */
  padding: 0;
}

/* Sticky, then pulled back up by its own height so the chapters lie over it
   rather than after it. */
.av-world {
  position: sticky;
  top: 0;
  height: 100svh;
  margin-bottom: -100svh;
  z-index: 0;
  overflow: hidden;
}

.av-sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, var(--sky-top) 0%, var(--haze) 62%, var(--sky-bottom) 100%);
}

.av-stars {
  position: absolute;
  inset: 0;
  opacity: calc((var(--p) - 0.72) * 3.4);
  background-image:
    radial-gradient(1.5px 1.5px at 12% 18%, #fff, transparent),
    radial-gradient(1px 1px at 28% 8%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 44% 24%, #fff, transparent),
    radial-gradient(1px 1px at 61% 12%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 73% 28%, #fff, transparent),
    radial-gradient(1px 1px at 86% 16%, #fff, transparent),
    radial-gradient(1px 1px at 35% 34%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 92% 38%, #fff, transparent),
    radial-gradient(1px 1px at 6% 42%, #fff, transparent),
    radial-gradient(1px 1px at 54% 44%, #fff, transparent);
}

.av-sun {
  position: absolute;
  left: 62%;
  top: calc(78% - var(--p) * 52%);
  width: clamp(120px, 18vw, 240px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, #fff6e2 0%, #ffe2ab 38%, rgba(255, 226, 171, 0) 70%);
  opacity: .85;
}

/* Absolute, or `bottom` does nothing and these become static blocks that flow
   down the page — which at scroll 0 happens to look like stacked ridges, and
   falls apart the moment the transforms move them. */
.av-layer {
  position: absolute;
  left: -4%;
  width: 108%;
  bottom: 0;
}

/* Height in vh rather than `auto`. With `height: auto` the ridge height is a
   function of viewport WIDTH, so on a phone the ridges collapse to a strip. */
.av-layer svg { display: block; width: 100%; height: 100%; }

.av-far   { height: 54vh; bottom: calc(30% + var(--p) * 5vh); transform: translateY(calc(var(--p) * -4vh * var(--travel))); }
.av-mid   { height: 52vh; bottom: calc(20% + var(--p) * 2vh); transform: translateY(calc(var(--p) * -9vh * var(--travel))); }
.av-near  { height: 50vh; bottom: calc(8% - var(--p) * 2vh);  transform: translateY(calc(var(--p) * -15vh * var(--travel))); }
.av-trees { height: 30vh; bottom: calc(-2% - var(--p) * 4vh); transform: translateY(calc(var(--p) * -22vh * var(--travel))); }
.av-fore  { height: 38vh; bottom: calc(-8% - var(--p) * 5vh); transform: translateY(calc(var(--p) * -28vh * var(--travel))); }

.av-far   path { fill: var(--rock-far); }
.av-mid   path { fill: var(--rock-mid); }
.av-near  path { fill: var(--rock-near); }
.av-trees path { fill: var(--rock-trees); }
.av-fore  path { fill: var(--rock-fore); }

.av-mid .av-snow { position: absolute; inset: 0; }
.av-mid .av-snow path { fill: #f1f4f6; opacity: calc(.25 + var(--p) * .6); }

.av-mist {
  position: absolute;
  left: 0; right: 0;
  height: 30vh;
  pointer-events: none;
  background: linear-gradient(to top, var(--haze), rgba(255,255,255,0));
}

/* Thins out with altitude — haze at the summit reads as a stray UI band. */
.av-mist-1 { bottom: calc(6% - var(--p) * 10vh); opacity: calc(.75 - var(--p) * .6); }
.av-mist-2 { bottom: calc(-6% - var(--p) * 22vh); opacity: calc(.55 - var(--p) * .45); }

/* The copy is light and the first sky is nearly white, so the text cannot
   rely on the scene for contrast. */
.av-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(12,19,25,.80) 0%, rgba(12,19,25,.62) 26%, rgba(12,19,25,.22) 52%, rgba(12,19,25,0) 72%),
    linear-gradient(0deg, rgba(12,19,25,.36) 0%, rgba(12,19,25,0) 26%);
}

/* Breaks up the banding a large flat gradient always shows. */
.av-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* The last layer of the world hands over to the page: by the end of the climb
   the scene has darkened to the site's own background, so the seam into the
   scroll world is a fade rather than an edge. */
.av-handoff {
  position: absolute;
  inset: auto 0 0 0;
  height: 26vh;
  pointer-events: none;
  opacity: var(--p);
  background: linear-gradient(to bottom, rgba(15,18,22,0), var(--paper));
}

.av-chapters { position: relative; z-index: 1; }

.av-chapter {
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: 0 clamp(22px, 6vw, 90px);
}

.av-inner { max-width: 34rem; }

.av-mark, .av-numeral, .av-hint {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .24em;
  text-transform: uppercase;
  line-height: 1;
}

.av-mark { margin: 0 0 26px; color: var(--av-ink); }
.av-numeral { margin: 0 0 16px; color: var(--av-accent); }

.av-chapter h1 {
  margin: 0 0 20px;
  font-family: var(--serif);
  font-size: clamp(40px, 6.6vw, 76px);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -.02em;
  text-shadow: 0 2px 24px rgba(12,19,25,.5);
}

.av-chapter h2 {
  margin: 0 0 16px;
  font-family: var(--serif);
  font-size: clamp(30px, 4.6vw, 50px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -.02em;
  text-shadow: 0 2px 20px rgba(12,19,25,.5);
}

.av-chapter h1 em, .av-chapter h2 em { font-style: italic; color: var(--av-accent); }

.av-chapter p:not(.av-mark):not(.av-numeral):not(.av-hint) {
  margin: 0 0 18px;
  font-size: 17.5px;
  line-height: 1.6;
  text-shadow: 0 1px 12px rgba(12,19,25,.55);
}

.av-hint { margin: 34px 0 0; opacity: .66; }

.av-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }

.av-hud {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex;
  justify-content: space-between;
  padding: 18px clamp(22px, 6vw, 90px);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .2em;
  color: var(--av-ink);
  text-shadow: 0 1px 8px rgba(12,19,25,.6);
  pointer-events: none;
  z-index: 2;
}

/* Without motion the parallax means nothing, so the layers settle where they
   are and every chapter is present from the start. */
@media (prefers-reduced-motion: reduce) {
  .av-chapter .av-inner { opacity: 1 !important; transform: none !important; }
}

/* A tall, narrow screen needs the ridges lifted and the travel shortened, or
   the layers march off the top and leave an empty sky at the summit. */
@media (max-width: 760px) {
  #ascent-vector { --travel: .5; }

  /* Wider than the screen on purpose: 1440 path units squeezed into 400px
     crams fifteen summits into a phone and they read as spikes. */
  .av-layer { left: -70%; width: 240%; }

  .av-far   { height: 34vh; bottom: calc(40% + var(--p) * 3vh); }
  .av-mid   { height: 32vh; bottom: calc(31% + var(--p) * 1vh); }
  .av-near  { height: 30vh; bottom: calc(20% - var(--p) * 2vh); }
  .av-trees { height: 20vh; bottom: calc(8% - var(--p) * 3vh); }
  .av-fore  { height: 28vh; bottom: calc(-2% - var(--p) * 4vh); }

  .av-mist { height: 22vh; }
  .av-mist-1 { bottom: calc(18% - var(--p) * 5vh); }
  .av-mist-2 { bottom: calc(4% - var(--p) * 11vh); }

  /* On a phone the copy spans the full width, so the wash has to come from
     the bottom rather than the left. */
  .av-scrim {
    background: linear-gradient(0deg, rgba(12,19,25,.82) 0%, rgba(12,19,25,.52) 38%, rgba(12,19,25,.12) 66%, rgba(12,19,25,0) 84%);
  }

  .av-chapter { align-items: flex-end; padding-bottom: 16vh; }
}

/* ============================================================
   The climb as a page background — every page other than the home page
   ============================================================
   Same scene, same climb, fixed behind the content. Scrolling a page IS the
   ascent: document progress drives --p exactly as section progress does on
   the home page, so reading the docs from top to bottom takes you from haze
   to starlight.

   The veil is heavier than the home page's but not opaque — these pages carry
   body copy, and ridges cutting through text at reading sizes is the failure
   mode to avoid. */

.av-backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;

  --p: 0;
  /* Shorter travel than the home page: a reading page is far taller than four
     screens, and full travel would run the layers off the top early. */
  --travel: .45;

  --sky-top: #8ba3b4;
  --sky-bottom: #cdc0ad;
  --haze: #cdc0ad;
  --rock-far: #8297a7;
  --rock-mid: #62798a;
  --rock-near: #455a6a;
  --rock-trees: #2d3e48;
  --rock-fore: #1a262d;
}

/* The reading surface. Strong enough that body copy always wins, light
   enough that the ridges and the changing sky are unmistakably there. */
.av-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    rgba(15, 18, 22, .62) 0%,
    rgba(15, 18, 22, .74) 45%,
    rgba(15, 18, 22, .80) 100%);
}

/* Pages carrying the backdrop must not paint over it. */
body.has-backdrop { background: transparent; }

/* Any full-width surface that was opaque on a solid page would hide the
   scene entirely. These become glass instead. */
body.has-backdrop .dark-band,
body.has-backdrop .cta-band,
body.has-backdrop .faq-band,
body.has-backdrop footer {
  background: rgba(15, 18, 22, .58);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

body.has-backdrop .card,
body.has-backdrop .cap-card,
body.has-backdrop .quote-card,
body.has-backdrop .doc-card,
body.has-backdrop .doc-note,
body.has-backdrop .model-table {
  background: rgba(21, 26, 33, .62);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* The docs sidebar sits directly on the scene — no panel, no blur. It is a
   short list of links with plenty of space around it, so it stays readable
   without a surface of its own, and the mountains carry straight through the
   full height of the page. */
body.has-backdrop .docs-aside,
body.has-backdrop .docs-nav,
body.has-backdrop .docs-nav-group {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-color: transparent;
}

/* Without a panel behind them the links need their own contrast. */
body.has-backdrop .docs-aside a {
  text-shadow: 0 1px 10px rgba(12, 19, 25, .75);
}

/* The current-section marker used the deep clay, which was chosen to hold up
   on ivory. Against the scene it goes muddy, so it takes the brighter clay. */
body.has-backdrop .docs-nav a[aria-current] {
  color: var(--clay);
}

/* ============================================================
   Burger menu — every page
   ============================================================
   The only piece of chrome on the site. It sits on the scene with no bar
   behind it, and opens a full-screen sheet rather than a dropdown, because
   there is no toolbar for a dropdown to hang from. */

.menu-toggle {
  position: fixed;
  top: clamp(18px, 2.4vw, 30px);
  right: clamp(18px, 2.4vw, 30px);
  z-index: 120;
  width: 44px;
  height: 44px;
  display: grid;
  align-content: center;
  gap: 5px;
  padding: 0 11px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  cursor: pointer;
  /* A 44pt target, which is the smallest thing a thumb reliably hits. */
  -webkit-tap-highlight-color: transparent;
}

.menu-toggle span {
  display: block;
  height: 1.5px;
  width: 100%;
  border-radius: 2px;
  background: var(--ivory-medium);
  box-shadow: 0 1px 6px rgba(12, 19, 25, .7);
  transition: transform .28s cubic-bezier(.2,0,0,1), opacity .18s;
}

.menu-toggle:hover span { background: #fff; }

.menu-toggle:focus-visible {
  outline: 2px solid var(--clay);
  outline-offset: 3px;
}

/* Becomes a cross while the sheet is open. */
.menu-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.menu-sheet {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  text-align: right;
  padding: 0 clamp(24px, 8vw, 120px);
  background: rgba(10, 14, 19, .82);
  backdrop-filter: blur(22px) saturate(120%);
  -webkit-backdrop-filter: blur(22px) saturate(120%);
  opacity: 0;
  transition: opacity .3s ease;
}

/* `hidden` is removed a frame before the class lands, so the sheet has
   something to transition from. */
.menu-sheet[hidden] { display: none; }
.menu-sheet.is-open { opacity: 1; }

.menu-sheet nav {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: clamp(2px, .8vh, 10px);
}

.menu-sheet a {
  color: var(--ivory-medium);
  text-decoration: none;
  font-family: var(--serif);
  font-size: clamp(28px, 5vw, 54px);
  line-height: 1.18;
  letter-spacing: -.02em;
  width: max-content;
  text-align: right;
  transition: color .2s;
}

.menu-sheet a:hover,
.menu-sheet a:focus-visible { color: var(--clay); }

.menu-sheet .menu-rule {
  height: 1px;
  width: min(320px, 60vw);
  margin: clamp(10px, 2vh, 22px) 0;
  margin-left: auto;
  background: rgba(240, 238, 230, .18);
}

.menu-sheet .menu-small {
  font-family: var(--sans);
  font-size: 15px;
  letter-spacing: 0;
  color: var(--ink-muted);
}

.menu-sheet .menu-small:hover { color: var(--ivory-medium); }

.menu-sheet .menu-cta {
  margin-top: clamp(12px, 2.4vh, 26px);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  padding: 12px 22px;
  border-radius: var(--r-pill);
  background: var(--ivory-light);
  color: var(--night-0);
}

.menu-sheet .menu-cta:hover { background: var(--clay); color: var(--ivory-light); }

/* The page behind the sheet must not scroll under it. */
body.menu-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .menu-toggle span, .menu-sheet { transition: none; }
}

/* ============================================================
   The mark
   ============================================================
   Inline SVG rather than an <img>, because the path is filled with
   `currentColor` — which only resolves inside the document. As an image it
   would be a black bitmap on a dark scene. */

.brand-fixed {
  position: fixed;
  top: clamp(18px, 2.4vw, 30px);
  left: clamp(18px, 2.4vw, 30px);
  z-index: 120;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--ivory-medium);
  /* The mark is a mountain silhouette; on a sky it needs its own edge. */
  filter: drop-shadow(0 1px 6px rgba(12, 19, 25, .75));
  transition: color .2s, transform .2s;
  -webkit-tap-highlight-color: transparent;
}

.brand-fixed:hover { color: #fff; transform: translateY(-1px); }

.brand-fixed:focus-visible {
  outline: 2px solid var(--clay);
  outline-offset: 3px;
  border-radius: 10px;
}

/* Hidden while the sheet is open, so it does not sit under the overlay. */
body.menu-open .brand-fixed { opacity: 0; pointer-events: none; }

.hud-brand { display: inline-flex; align-items: center; gap: 7px; }
.hud-mark { color: inherit; }

/* The footer mark inherits the footer's own text colour. */
.brand-mark { color: currentColor; vertical-align: -6px; }
