@import url("https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Fraunces:opsz,wght@9..144,100..900&family=Instrument+Sans:wght@400..700&display=swap");

:root {
  --paper: #f3eddf;
  --paper-deep: #e7dcc5;
  --ink: #293229;
  --moss: #50664f;
  --faded: #778273;
  --rule: rgba(61, 70, 56, .28);
  --font-sans: "Instrument Sans", system-ui, sans-serif;
  --font-serif: "Fraunces", Georgia, serif;
  --font-mono: "DM Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }
html { background: var(--paper); scroll-behavior: smooth; }
body { margin: 0; overflow-x: hidden; color: var(--ink); background: var(--paper); font-family: var(--font-sans); }
body.reader-open { overflow: hidden; }
button, input { color: inherit; font: inherit; }
button { cursor: pointer; }
.hidden { display: none !important; }
.skip-link { position: fixed; z-index: 100; top: -5rem; left: 1rem; padding: .75rem 1rem; background: #fffdf5; border: 1px solid var(--ink); }
.skip-link:focus { top: 1rem; }

.topbar {
  position: fixed; z-index: 30; inset: 0 0 auto; height: 4.8rem;
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 2.6rem; color: #2e382d; mix-blend-mode: multiply;
}
.brand, .atlas-link { border: 0; background: transparent; }
.brand { display: flex; align-items: center; gap: .6rem; padding: 0; letter-spacing: -.035em; }
.brand-mark { width: 1.9rem; aspect-ratio: 1; display: grid; place-items: center; border: 1px solid; border-radius: 50%; font-family: var(--font-serif); font-weight: 600; }
.top-actions { display: flex; align-items: center; gap: 1.25rem; }
.top-actions > span { font: 500 .67rem var(--font-mono); letter-spacing: .12em; }
.atlas-link { padding: .25rem 0; font-size: .83rem; font-weight: 650; text-decoration: underline; text-underline-offset: .27rem; }

.journey-nav { position: fixed; z-index: 30; top: 50%; left: 2.55rem; transform: translateY(-50%); display: grid; gap: .42rem; }
.journey-nav button { display: flex; align-items: center; gap: .55rem; padding: .12rem 0; border: 0; background: transparent; color: rgba(42, 52, 41, .58); font: .62rem var(--font-mono); }
.journey-nav i { display: block; width: 0; height: 1px; background: currentColor; transition: width .3s ease; }
.journey-nav button.active { color: var(--ink); }
.journey-nav button.active i { width: 1.45rem; }

.zoom-journey { height: 780vh; position: relative; background: var(--paper); }
.fixed-stage { position: sticky; top: 0; height: 100svh; overflow: hidden; isolation: isolate; background: var(--paper); }
.scene-layer { position: absolute; inset: -2%; margin: 0; will-change: transform, opacity, clip-path; }
.scene-layer img { width: 100%; height: 100%; display: block; object-fit: cover; }
.paper-grain { position: absolute; z-index: 8; inset: 0; pointer-events: none; background: url('../scenes/cotton-paper.webp') center / 540px repeat; mix-blend-mode: multiply; opacity: .13; }
.stage-wash { position: absolute; z-index: 7; inset: 0; pointer-events: none; background: linear-gradient(90deg, rgba(246,241,228,.64), rgba(246,241,228,.08) 52%, transparent 76%), linear-gradient(0deg, rgba(41,50,41,.18), transparent 45%); }
.caption-wrap { position: absolute; z-index: 12; left: clamp(1.5rem, 7vw, 7rem); bottom: clamp(4.5rem, 10vh, 7rem); width: min(40rem, 78vw); will-change: opacity; }
.scene-caption { animation: caption-in .55s ease both; text-shadow: 0 1px 22px rgba(250,247,237,.9); }
.scene-kicker, .scene-eyebrow, .atlas-kicker, .reader-kicker { font: 500 .68rem var(--font-mono); letter-spacing: .13em; text-transform: uppercase; }
.scene-kicker { margin: 0 0 .75rem; color: var(--moss); }
.scene-eyebrow { margin: 0 0 .35rem; color: #53654f; letter-spacing: .08em; }
.scene-caption h1 { margin: 0; max-width: 10ch; font: 500 clamp(3.8rem, 7.4vw, 7.2rem)/.87 var(--font-serif); letter-spacing: -.068em; }
.scene-note { max-width: 32rem; margin: 1.2rem 0 1.55rem; font-size: 1.06rem; line-height: 1.5; }
.read-chapter { padding: .7rem 1rem; border: 1px solid rgba(43,53,42,.52); border-radius: 999px; background: rgba(249,246,236,.7); font-size: .82rem; transition: transform .2s ease, background .2s ease; }
.read-chapter:hover { transform: translateY(-2px); background: #fbf8ed; }
.read-chapter span { margin-left: .4rem; }
.scroll-cue { position: absolute; z-index: 12; right: 2.65rem; bottom: 2rem; display: flex; align-items: center; gap: .55rem; margin: 0; font: .62rem var(--font-mono); letter-spacing: .12em; text-transform: uppercase; }
.scroll-cue b { font-size: .9rem; }
.image-fallback { position: absolute; inset: 0; display: grid; place-items: center; background: var(--paper); color: var(--faded); font: .7rem var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }

.docs-atlas { position: relative; min-height: 100svh; overflow: hidden; background: var(--paper); border-top: 1px solid var(--rule); }
.docs-atlas::after { content: ""; position: absolute; z-index: 2; inset: 0; pointer-events: none; background: url('../scenes/cotton-paper.webp') center / 540px repeat; mix-blend-mode: multiply; opacity: .14; }
.atlas-art { position: absolute; inset: 0; background: linear-gradient(90deg, rgba(244,237,221,.97) 0%, rgba(244,237,221,.89) 48%, rgba(244,237,221,.34) 100%), url('../scenes/field-atlas.webp') center / cover no-repeat; }
.atlas-content { position: relative; z-index: 4; width: min(72rem, calc(100% - 3rem)); margin: 0 auto; padding: clamp(6rem, 10vw, 9rem) 0; }
.atlas-kicker { margin: 0 0 .8rem; color: var(--moss); }
.atlas-content h2, .reader h2 { font-family: var(--font-serif); font-weight: 500; letter-spacing: -.065em; }
.atlas-content h2 { margin: 0; font-size: clamp(4rem, 9vw, 8rem); line-height: .82; }
.atlas-intro { max-width: 34rem; margin: 1.35rem 0 2.5rem; line-height: 1.55; }
.search-field { display: grid; gap: .45rem; max-width: 41rem; margin-bottom: 2.5rem; color: var(--moss); font: .65rem var(--font-mono); letter-spacing: .11em; text-transform: uppercase; }
.search-field input { width: 100%; padding: .85rem 0; border: 0; border-bottom: 1px solid rgba(57,71,54,.58); outline: 0; background: transparent; font: 1rem var(--font-sans); text-transform: none; letter-spacing: normal; }
.search-field input:focus { border-color: var(--ink); }
.atlas-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 56rem; border-top: 1px solid var(--rule); border-left: 1px solid var(--rule); }
.atlas-card { min-height: 11rem; padding: 1.2rem; display: flex; flex-direction: column; align-items: flex-start; text-align: left; border: 0; border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule); background: rgba(247,242,229,.6); transition: background .2s ease; }
.atlas-card:hover { background: rgba(230,223,202,.78); }
.atlas-number { color: var(--faded); font: .62rem var(--font-mono); letter-spacing: .1em; }
.atlas-card strong { margin: .7rem 0 .35rem; font: 500 1.35rem var(--font-serif); letter-spacing: -.025em; }
.atlas-card > span:nth-child(3) { max-width: 25rem; font-size: .82rem; line-height: 1.45; }
.atlas-card i { margin-top: auto; padding-top: .8rem; color: var(--moss); font-size: .72rem; font-style: normal; text-decoration: underline; text-underline-offset: .22rem; }
.empty-results { max-width: 56rem; padding: 2rem 0; color: var(--moss); }

.reader-backdrop { position: fixed; z-index: 80; inset: 0; display: grid; place-items: center; padding: 1.2rem; background: rgba(38,45,36,.55); backdrop-filter: blur(8px); }
.backdrop-close { position: absolute; inset: 0; border: 0; background: transparent; }
.reader { position: relative; z-index: 1; width: min(43rem, 100%); max-height: calc(100svh - 2.4rem); overflow: auto; padding: clamp(2rem, 5vw, 4.5rem); background: #f6efde url('../scenes/cotton-paper.webp') center / 520px repeat; box-shadow: 0 2rem 6rem rgba(16,20,15,.33); }
.reader-close { position: absolute; top: 1.1rem; right: 1.3rem; border: 0; background: transparent; font: 2rem/1 var(--font-serif); }
.reader-kicker { margin: 0; color: var(--moss); }
.reader h2 { margin: .75rem 0 1.35rem; font-size: clamp(3rem, 7vw, 5.4rem); line-height: .88; }
.reader > p:not(.reader-kicker) { font-size: 1.08rem; line-height: 1.67; }
.code-block { margin-top: 2rem; padding: 1rem 1.15rem; border-radius: .2rem; background: #29332a; color: #ece8dc; font: .77rem/1.72 var(--font-mono); }
.code-block div { display: flex; justify-content: space-between; color: #b9c5b1; }
.code-block button { border: 0; background: transparent; color: inherit; text-decoration: underline; }
.code-block pre { margin: .75rem 0 0; white-space: pre-wrap; }
.reader footer { margin-top: 2.5rem; padding-top: 1.2rem; display: flex; justify-content: space-between; border-top: 1px solid var(--rule); font: .65rem var(--font-mono); letter-spacing: .1em; text-transform: uppercase; }
.reader footer button { border: 0; background: transparent; color: var(--moss); text-decoration: underline; }

.static-journey { display: none; }
.noscript-note { min-height: 100vh; display: grid; place-content: center; max-width: 42rem; margin: auto; padding: 2rem; }
@keyframes caption-in { from { opacity: 0; transform: translateY(12px); } }

@media (max-width: 720px) {
  .topbar { height: 4.2rem; padding: 0 1.15rem; }
  .top-actions > span { display: none; }
  .journey-nav { top: auto; bottom: 1.25rem; left: 50%; transform: translateX(-50%); display: flex; gap: .45rem; }
  .journey-nav button span { display: none; }
  .journey-nav i, .journey-nav button.active i { width: .45rem; height: .45rem; border-radius: 50%; background: currentColor; }
  .zoom-journey { height: 640vh; }
  .scene-layer { inset: 0; }
  .scene-layer img { object-position: 58% center; }
  .caption-wrap { left: 1.3rem; bottom: 4.4rem; width: calc(100% - 2.6rem); }
  .scene-caption h1 { font-size: clamp(3.3rem, 15vw, 4.8rem); }
  .scene-note { max-width: 23rem; font-size: .96rem; }
  .scroll-cue { display: none; }
  .atlas-content { width: min(100% - 2.4rem, 44rem); }
  .atlas-grid { grid-template-columns: 1fr; }
  .atlas-content h2 { font-size: clamp(4rem, 19vw, 6rem); }
  .reader { padding: 3.7rem 1.5rem 2rem; }
  .reader footer { align-items: flex-start; flex-direction: column; gap: .8rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .zoom-journey { display: none; }
  .static-journey { display: block; }
  .static-scene { position: relative; min-height: 100svh; overflow: hidden; display: flex; align-items: flex-end; padding: 7rem max(7vw, 6rem) 5rem; }
  .static-scene > img { position: absolute; z-index: -2; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .static-scene::after { content: ""; position: absolute; z-index: -1; inset: 0; background: linear-gradient(90deg, rgba(245,239,225,.68), transparent 72%); }
  .static-scene .scene-caption { width: min(39rem, 78vw); }
  .read-chapter, .atlas-card { transition: none; }
}

/* ─────────────────────────────────────────────────────────────────────
   Legibility over the illustrations
   ─────────────────────────────────────────────────────────────────────
   The artwork is the point, so nothing here covers it. These rules only
   give the floating UI enough ground to be readable on every scene.

   Two root causes, both measured rather than guessed:

   1. `.topbar` used `mix-blend-mode: multiply`. Dark ink multiplied over
      dark foliage resolves to dark — the brand and the "Docs atlas" link
      were effectively invisible on Repository Canopy and Watcher Bird.
   2. `.stage-wash` fades to fully transparent at 76% width, and the
      scene counter, atlas link and scroll cue all sit past that. They
      had no ground at all.

   The technique is the paper glow `.scene-caption` already uses, so this
   reads as the same design language rather than a patch.
   ──────────────────────────────────────────────────────────────────── */

:root {
  /* Paper-coloured halo — lifts dark ink off a busy background without
     drawing a box around it. */
  --glow-paper: 0 0 2px rgba(250, 247, 237, .92), 0 1px 16px rgba(250, 247, 237, .95);
  /* The inverse, for the darkened bottom edge of the stage. */
  --glow-ink: 0 0 2px rgba(28, 35, 28, .55), 0 1px 14px rgba(28, 35, 28, .7);
}

/* ── Top bar ──────────────────────────────────────────────────────── */
.topbar {
  /* multiply is what broke this; normal + a soft scrim keeps the art
     visible while giving the controls somewhere to sit. */
  mix-blend-mode: normal;
}

.topbar::before {
  content: "";
  position: absolute;
  /* Extends past the bar so the fade is gradual — a hard edge would read
     as a UI chrome bar sitting on top of a painting. */
  inset: 0 0 -3.4rem;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(243, 237, 223, .9),
    rgba(243, 237, 223, .45) 46%,
    transparent
  );
}

.brand,
.atlas-link,
#scene-counter {
  text-shadow: var(--glow-paper);
}

/* Was 10.7px — below comfortable reading size for a light mono face. */
#scene-counter { font-size: .72rem; }

/* ── Chapter rail ─────────────────────────────────────────────────── */
.journey-nav button {
  /* .58 alpha over a busy wash left the inactive numerals hard to read;
     the active one was fine because it uses full --ink. */
  color: rgba(42, 52, 41, .74);
  font-size: .68rem;
  text-shadow: var(--glow-paper);
}

/* ── Scroll cue ───────────────────────────────────────────────────── */
.scroll-cue {
  /* Sits in the bottom-right, where stage-wash *darkens* rather than
     lightens. Fighting that with dark ink and a paper halo would look
     muddy, so this flips to paper-on-ink and works with the vignette
     that is already there. */
  color: rgba(250, 247, 237, .94);
  font-size: .68rem;
  text-shadow: var(--glow-ink);
}

/* ── Stage wash ───────────────────────────────────────────────────── */
.stage-wash {
  background:
    /* Left wash, carried further right and held higher through the middle.
       Measured: at chapter 3 the original .64/52%/76% ramp left the kicker
       and eyebrow — 10.9px uppercase mono, the most fragile type here — at
       2.8:1. The focal subject of every scene sits centre-right, so the
       extra opacity lands on background foliage, not on the drawing. */
    linear-gradient(90deg,
      rgba(246, 241, 228, .82),
      rgba(246, 241, 228, .34) 38%,
      rgba(246, 241, 228, .08) 62%,
      transparent 78%),
    /* New: a narrow lift at the right edge only, so the counter and
       atlas link have ground without washing out the focal subject —
       the bird and the tree both sit centre-right. */
    linear-gradient(270deg, rgba(246, 241, 228, .34), rgba(246, 241, 228, .1) 9%, transparent 17%),
    /* Slightly deeper than before, to carry the now-light scroll cue. */
    linear-gradient(0deg, rgba(41, 50, 41, .26), transparent 42%);
}

/* ── Captions ─────────────────────────────────────────────────────── */
/* 10.9px uppercase mono with .13em tracking is the most fragile type on
   the page — thin strokes, wide gaps, and it sits at the TOP of the
   caption where the left wash has already begun to fall away. The moss
   tint the original used (#5c7154-ish) measured 2.8:1 over chapter 3.
   Held near --ink and given a denser halo than the caption body, these
   clear 4.5:1 on every scene while still reading as a label rather than
   a heading. */
.scene-kicker  { color: #333f2e; }
.scene-eyebrow { color: #35422f; }
.scene-kicker,
.scene-eyebrow {
  text-shadow:
    0 0 1px rgba(250, 247, 237, .95),
    0 0 6px rgba(250, 247, 237, .95),
    0 1px 12px rgba(250, 247, 237, .9);
}

.scene-caption {
  /* Tighter and stronger than the original 22px spread, which diffused
     too far to actually lift 17px body copy off moving water. */
  text-shadow: 0 0 2px rgba(250, 247, 237, .8), 0 1px 16px rgba(250, 247, 237, .96);
}

@media (max-width: 720px) {
  /* The left wash is proportionally narrower on a phone, so the caption
     spans the full width and the body copy ends up over open water. A
     local scrim behind just the caption fixes it without touching the
     scene. */
  .caption-wrap::before {
    content: "";
    position: absolute;
    inset: -1.4rem -1.3rem -1.6rem;
    z-index: -1;
    pointer-events: none;
    background: linear-gradient(
      180deg,
      transparent,
      rgba(243, 237, 223, .72) 18%,
      rgba(243, 237, 223, .86) 55%,
      rgba(243, 237, 223, .9)
    );
  }
  .caption-wrap { isolation: isolate; }
}

@media (prefers-contrast: more) {
  /* Readers who have asked for more contrast get the wash turned up
     rather than a different layout. */
  .stage-wash {
    background:
      linear-gradient(90deg, rgba(246, 241, 228, .86), rgba(246, 241, 228, .3) 58%, rgba(246, 241, 228, .12) 80%),
      linear-gradient(0deg, rgba(41, 50, 41, .34), transparent 42%);
  }
  .scene-kicker, .scene-eyebrow { color: #232c20; }
}


/* ── Scroll cue, chapter rail: local scrims ───────────────────────────
   These two float over whatever the scene happens to put underneath
   them, so a gradient tied to the stage cannot guarantee anything. Each
   gets its own soft halo instead — measured floor rather than a hope
   about the artwork.
   ──────────────────────────────────────────────────────────────────── */

.scroll-cue { isolation: isolate; }
.scroll-cue::before {
  content: "";
  position: absolute;
  inset: -1rem -1.5rem -1.1rem -1.7rem;
  z-index: -1;
  pointer-events: none;
  /* Radial, not a rectangle — no visible edge against the drawing.
     Chapter 6 ends on bright water, where the ink-side cue measured
     2.2:1 against the stage vignette alone. */
  background: radial-gradient(
    ellipse at center,
    rgba(26, 33, 26, .58),
    rgba(26, 33, 26, .34) 55%,
    transparent 76%
  );
}

@media (max-width: 720px) {
  /* The rail collapses to a dot row at the foot of the stage on a phone,
     which is exactly where several scenes put dark rock — the active dot
     measured 1.0:1 there, i.e. invisible. */
  .journey-nav { isolation: isolate; }
  .journey-nav::before {
    content: "";
    position: absolute;
    inset: -.7rem -1.1rem;
    z-index: -1;
    pointer-events: none;
    border-radius: 999px;
    background: radial-gradient(
      ellipse at center,
      rgba(246, 241, 228, .88),
      rgba(246, 241, 228, .6) 58%,
      transparent 80%
    );
  }
}
