/* =========================================================
   The Longing House
   Marriage, Myth, and Tourism in Coastal Hainan
   ---------------------------------------------------------
   One dark theme. Each chapter is one continuous canvas of
   photographs that moves inside a viewport-sized window
   while the field notes read beside them on a soft, see-
   through darkening (see js/main.js). Without JavaScript or
   with reduced motion, everything simply flows top to bottom
   and each journal sits after its chapter's photographs.
   ========================================================= */

/* ---------- Fonts ----------
   Headings: GT Sectra (Grilli Type), with Spectral standing in
   until the licensed files are dropped into fonts/ and the block
   below is uncommented. The heading stack already lists GT Sectra
   first, so nothing else changes.
   Body: Roboto, self-hosted. Both families are reached through
   --font-heading and --font-body, so a future swap is one line. */

/*
@font-face {
  font-family: "GT Sectra";
  src: url("../fonts/GT-Sectra-Book.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
*/

@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-300-normal.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-300-italic.woff2") format("woff2");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Spectral";
  src: url("../fonts/spectral-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("../fonts/roboto-variable-normal.woff2") format("woff2");
  font-weight: 300 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("../fonts/roboto-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

/* ---------- Tokens ---------- */

:root {
  color-scheme: dark;

  --bg: #0C0D0E;
  --bg-rgb: 12, 13, 14;
  --fg: #E5E6E4;
  --fg-soft: rgba(229, 230, 228, 0.74);
  --fg-muted: rgba(229, 230, 228, 0.5);
  --fg-faint: rgba(229, 230, 228, 0.2);

  --ch-vanishing: #3D2420;
  --ch-performance: #2E1B19;
  --ch-displacement: #1F1213;

  --font-heading: "GT Sectra", "Spectral", "Iowan Old Style", Georgia, serif;
  --font-body: "Roboto", -apple-system, "Helvetica Neue", Helvetica, Arial, sans-serif;

  --gutter: clamp(1.25rem, 6vw, 5rem);
  --panel-w: clamp(19rem, 28vw, 26rem);   /* width of the journal text column on wide screens */
  --scrim-w: min(54vw, 48rem);            /* width of its darkening, which fades out to the left */
  --measure: 40rem;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------- Reset ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}
/* Photographs keep their shape before they load, so the page is
   measured the same whether or not they have arrived. */
img[width="2048"] { aspect-ratio: 2048 / 1365; }
img[width="1365"] { aspect-ratio: 1365 / 2048; }

h1, h2, h3, h4, p, figure, ul {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

::selection {
  background: rgba(229, 230, 228, 0.18);
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

.hero__img {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 130%;
  object-fit: cover;
  object-position: 50% 40%;
  will-change: transform;
  /* The photograph dissolves into the dark at its lower edge. */
  -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}

/* One flat darkening so the title reads on any crop. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(var(--bg-rgb), 0.24);
  pointer-events: none;
}

.hero__text {
  position: relative;
  z-index: 1;
  padding: 0 var(--gutter) 15vh;
  max-width: 60rem;
}
.js .hero__text {
  animation: hero-in 1.6s var(--ease) both;
  animation-delay: 0.2s;
}
@keyframes hero-in {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

.hero__title {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(2.6rem, 6.2vw, 5.4rem);
  line-height: 1.02;
  letter-spacing: -0.012em;
}

.hero__subtitle {
  margin-top: 1.1rem;
  font-size: clamp(0.95rem, 1.2vw, 1.1rem);
  line-height: 1.5;
  opacity: 0.86;
}

.hero__byline {
  margin-top: 1.4rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-soft);
}

.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 2.25rem;
  z-index: 1;
  width: 1px;
  height: 2.75rem;
  transform: translateX(-50%);
  background: rgba(229, 230, 228, 0.35);
  overflow: hidden;
}
.scroll-cue span {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 40%;
  background: var(--fg);
  opacity: 0.85;
  animation: cue-drop 2.4s var(--ease) infinite;
}
@keyframes cue-drop {
  0%   { transform: translateY(-100%); }
  60%  { transform: translateY(260%); }
  100% { transform: translateY(260%); }
}

/* ---------- Text pages: statement, chapter openings, closing ----------
   Each is a full screen of quiet with words in the middle. Their
   words rise and fade in and out with scroll (main.js). The
   chapter openings are colored, and their color dissolves at the
   top and bottom instead of stopping at a line. */

.page {
  position: relative;
  z-index: 2;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: 12vh var(--gutter);
  text-align: center;
}

.page__inner {
  max-width: 36rem;
}

.statement__inner {
  max-width: var(--measure);
  text-align: left;
  font-size: clamp(1.05rem, 1.35vw, 1.2rem);
  line-height: 1.7;
}
.statement__inner p + p {
  margin-top: 1.5em;
}

.transition {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 84%, transparent 100%);
}

/* With motion, each text page is taller than the window and its
   words stick to the window while the page passes. They do not
   scroll: main.js fades them in once the page has settled, holds
   them, and fades them out before it moves on. */
.stack .page {
  display: block;
  min-height: 170vh;
  padding: 0;
}
.stack .page__inner {
  position: sticky;
  top: 0;
  height: 100vh;
  max-width: none;
  display: grid;
  align-content: center;
  justify-items: center;
  padding: 0 var(--gutter);
  will-change: opacity;
}
.stack .page__inner > * {
  width: 100%;
  max-width: 36rem;
}
.stack .statement__inner > * {
  max-width: var(--measure);
}
.stack .transition {
  margin: -12vh 0;
  min-height: 170vh;
}
.stack .closing {
  min-height: 135vh;
}
.transition--vanishing    { background: var(--ch-vanishing); }
.transition--performance  { background: var(--ch-performance); }
.transition--displacement { background: var(--ch-displacement); }

/* ---------- Totem watermark on the chapter openings ----------
   A Li textile motif, tiled faintly behind the chapter title and
   its epigraph: the deer (鹿纹) for Vanishing, the guardian deity
   (大力神) for Performance, the bird (鸟纹) for Displacement.
   Chapter openings only; nothing else on the page carries it.

   The artwork is Katherine's, in totem-patterns/: white line art
   on transparent ground. Each opening reaches its own through
   --totem, so swapping one is a single line. The three are not
   the same shape, so the tile is sized by width and the height
   follows. */

.transition--vanishing    { --totem: url("../totem-patterns/luwen-vanishing.png"); }
.transition--performance  { --totem: url("../totem-patterns/dalishen-performance.png"); }
.transition--displacement { --totem: url("../totem-patterns/niaowen-displacement.png"); }

.transition::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--totem);
  background-repeat: repeat;
  background-position: center;
  background-size: clamp(130px, 12vw, 190px);
  opacity: 0.038;
}
.transition .page__inner {
  position: relative;
  z-index: 1;
}
.stack .transition .page__inner {
  position: sticky;
}

.transition__title {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(2.6rem, 6.5vw, 5.2rem);
  line-height: 1;
  letter-spacing: -0.01em;
}

.transition__text {
  margin-top: 1.75rem;
  font-size: clamp(1rem, 1.25vw, 1.125rem);
  line-height: 1.65;
  opacity: 0.86;
}

.fulltext__line {
  max-width: 30em;
  margin: 0 auto;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(1.45rem, 2.6vw, 2.15rem);
  line-height: 1.4;
}

/* ---------- Chapters ----------
   .chapter__body is given a height by main.js (from the length
   of the journal). Inside it, .chapter__view sticks to the
   viewport and the image canvas moves through it. */

.chapter__body {
  position: relative;
  z-index: 1;
}

.chapter__view {
  position: relative;
}
.stack .chapter__view {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.chapter__images {
  position: relative;
  padding: 10vh 0 12vh;
}
.stack .chapter__images {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  padding: 0;
  will-change: transform;
}

/* ---------- Photographs ----------
   Each photograph is large. Full-width ones fill the window and
   dissolve at their top and bottom edges. The ones with a caption
   below run wide enough to pass under the journal's darkening.
   With motion (.stack) they are stacked by main.js so that each
   overlaps the tail of the one before it; earlier photographs sit
   above later ones, so a leaving photograph dissolves over the
   arriving one and captions are never covered. Without motion
   they simply flow, centred. */

.pic {
  position: relative;
}
.stack .pic {
  position: absolute;
  left: 0;
  margin: 0;
  will-change: transform, opacity;
}

/* Photograph with its caption below. */
.pic--column {
  width: min(72vw, 128vh);
  margin: 0 auto 14vh;
}
.pic__inner {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}
.pic--column .pic__img {
  width: 100%;
  height: auto;
}
.pic--portrait {
  width: auto;
  display: flex;
  justify-content: center;
}
.pic--portrait .pic__inner {
  width: auto;
}
.pic--portrait .pic__img {
  width: auto;
  height: 86vh;
  max-width: 100%;
}
.pic--column figcaption {
  margin-top: 1.35rem;
  max-width: min(46ch, 100%);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--fg-soft);
}
.stack .pic--column {
  left: 5vw;
}
/* Where a caption may pass over the photograph arriving beneath
   it, it reads on a soft darkening that fades out to the right and
   at its top and bottom, like the journal's. */
.stack .pic--column figcaption {
  position: relative;
  margin-top: 0;
  padding: 1.35rem 5rem 1.5rem 0;
  max-width: min(46ch + 5rem, 100%);
  color: var(--fg);
}
.stack .pic--column figcaption::before {
  content: "";
  position: absolute;
  inset: -0.75rem -3rem -0.75rem -3rem;
  z-index: -1;
  background: linear-gradient(to right, rgba(var(--bg-rgb), 0.78) 0%, rgba(var(--bg-rgb), 0.7) 55%, rgba(var(--bg-rgb), 0) 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 28%, #000 72%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 28%, #000 72%, transparent 100%);
}
.stack .pic--column:nth-child(even of .pic--column) {
  left: 12vw;
}
.stack .pic--portrait {
  left: 8vw;
  display: block;
}
.stack .pic--portrait:nth-child(even of .pic--column) {
  left: 20vw;
}

/* Full-width photograph. Its top and bottom edges dissolve so it
   blends into the dark and into its neighbours. */
.pic--bleed {
  width: 100%;
  height: 100vh;
  margin: 0 0 10vh;
}
.pic--bleed .pic__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
}
.pic--bleed-portrait {
  display: flex;
  justify-content: center;
}
.pic--bleed-portrait .pic__img {
  position: static;
  width: auto;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
}
.stack .pic--bleed-portrait {
  left: 7vw;
  width: auto;
  display: block;
}

/* Caption in the corner of a full-width photograph, on a soft
   darkening that fades out to the right. */
.fig__corner {
  position: absolute;
  left: 0;
  bottom: 10vh;
  z-index: 1;
  max-width: calc(30ch + var(--gutter) + 6rem);
  padding: 1.6rem 6rem 1.6rem var(--gutter);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fg);
  background: linear-gradient(to right, rgba(var(--bg-rgb), 0.72) 0%, rgba(var(--bg-rgb), 0.6) 55%, rgba(var(--bg-rgb), 0) 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 30%, #000 70%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 30%, #000 70%, transparent 100%);
}

/* Two photographs side by side, thin divider. */
.pic--pair {
  width: min(84vw, 150vh);
  margin: 0 auto 14vh;
}
.stack .pic--pair {
  left: 5vw;
}
.fig__pair {
  display: flex;
  align-items: stretch;
  justify-content: flex-start;
  height: 62vh;
  max-width: 100%;
}
.fig__pair .pic__img {
  height: 100%;
  width: auto;
  max-width: none;
  flex: 0 1 auto;
  min-width: 0;
  object-fit: contain;
}
.fig__divider {
  flex: 0 0 1px;
  margin: 0 clamp(1rem, 2.5vw, 2rem);
  background: var(--fg-faint);
}

/* A line of text set into the flow of photographs. */
.pic--line {
  width: min(72vw, 128vh);
  min-height: 80vh;
  margin: 0 auto 8vh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 0 var(--gutter);
}
.stack .pic--line {
  left: 0;
  width: 62vw;
  min-height: 90vh;
  z-index: 60 !important;   /* the line is never covered by a photograph */
}

/* ---------- Field notes ----------
   In flow (reduced motion, no JavaScript): a reading block after
   the chapter's photographs.
   With motion (.stack): laid over the chapter's window. The text
   sits on a darkening that is see-through and fades out away from
   the edge, so the photographs stay present beneath it. The text
   is moved by scroll at a steady reading rate (main.js). */

.notes {
  position: relative;
  z-index: 1;
  padding: clamp(5rem, 14vh, 9rem) var(--gutter);
}

.notes__scrim {
  display: none;
}

.notes__scroll {
  max-width: var(--measure);
  margin: 0 auto;
}

.notes__text {
  font-size: 1rem;
  line-height: 1.75;
  color: var(--fg-soft);
}
.notes__text p + p {
  margin-top: 1.3em;
}

.notes__label {
  font-size: 0.8125rem;
  color: var(--fg-muted);
}

.notes__heading {
  margin: 0.75rem 0 2rem;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(1.7rem, 2.6vw, 2.1rem);
  line-height: 1.15;
  color: var(--fg);
}
.notes__heading span {
  display: block;
  margin-top: 0.4rem;
  font-family: var(--font-body);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--fg-muted);
}

/* Date labels within a journal: small, letter-spaced, set above
   the entry they open. */
.notes__entry {
  margin: 2.5rem 0 1rem;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
}
.notes__text p + .notes__entry {
  margin-top: 3rem;
}
.notes__heading + .notes__entry {
  margin-top: 0;
}

.notes__credit {
  color: var(--fg-muted);
}

/* Sentences Katherine marked. Weight alone, no color shift, so
   they read as emphasis inside the paragraph rather than as a
   second voice. */
.notes__text strong {
  font-weight: 500;
  color: var(--fg);
}

/* ---------- Scroll-linked reading ----------
   With motion, a reading line travels the journal as the chapter
   scrolls (main.js). The entry under it is at full strength; the
   ones already read and the ones still coming are held well back,
   so the eye knows where it is. The panel's own title is not one
   of the entries and holds its own strength throughout. Without
   motion every entry reads at full strength. */
.stack .notes__text > p,
.stack .notes__text > .notes__entry {
  opacity: 0.26;
  transition: opacity 0.45s var(--ease);
  will-change: opacity;
}
.stack .notes__text > .is-active {
  opacity: 1;
}
/* The panel's standing title is not one of the entries, so it
   neither dims nor lights. It is held out by a later rule of the
   same weight rather than by a :not() on the rule above — adding a
   class to that selector would push it past .is-active and stop
   every entry from ever lighting. */
.stack .notes__text > .notes__label {
  opacity: 1;
}

.stack .notes {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--scrim-w);
  padding: 0;
  opacity: 0;
  pointer-events: none;
}
.stack .notes__scrim {
  display: block;
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to right,
    rgba(var(--bg-rgb), 0) 0%,
    rgba(var(--bg-rgb), 0.42) 34%,
    rgba(var(--bg-rgb), 0.74) 58%,
    rgba(var(--bg-rgb), 0.8) 100%
  );
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 14%, #000 86%, transparent 100%);
}
.stack .notes__scroll {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--panel-w);
  max-width: none;
  margin: 0;
  padding: 18vh 3rem 18vh 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 84%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 84%, transparent 100%);
}
.stack .notes__text {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--fg);
  will-change: transform;
}
.stack .notes__heading {
  font-size: 1.6rem;
}

/* A full-bleed photograph gets the whole window. While one is the
   photograph in view the journal is gone entirely, not merely
   faint — nothing reads on top of it. main.js sets the fade
   itself (it owns this element's opacity) and adds this class at
   the point the journal is out of the way, so anything else that
   asks can tell. */
.stack .notes--hidden {
  pointer-events: none;
}

/* ---------- Footer ---------- */

.footer {
  position: relative;
  z-index: 2;
  background: var(--bg);
  padding: clamp(3rem, 8vh, 5rem) var(--gutter) clamp(2.5rem, 6vh, 4rem);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--fg-muted);
}

.footer__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 2.5rem;
}

/* The name carries the piece, so it is set well above the rest of
   the row rather than sitting inside it. */
.footer__name {
  font-family: var(--font-heading);
  font-size: clamp(1.5rem, 3vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--fg);
  flex: 1 0 100%;
  margin-bottom: 0.35rem;
}

/* ---------- Gallery ----------
   Every photograph from the project, after the piece has ended.
   Flat and evenly spaced on purpose: the chapters carry the
   sequencing, so this is a plate section, not more narrative.
   Built from the list in js/gallery.js. */

.gallery {
  position: relative;
  z-index: 2;
  background: var(--bg);
  padding: clamp(5rem, 14vh, 9rem) var(--gutter) clamp(3rem, 8vh, 5rem);
}

.gallery__heading {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(1.7rem, 3.2vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin-bottom: 2.5rem;
}

.gallery__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(0.5rem, 1.2vw, 1rem);
}

.gallery__item {
  appearance: none;
  border: 0;
  padding: 0;
  margin: 0;
  background: rgba(229, 230, 228, 0.04);
  cursor: zoom-in;
  overflow: hidden;
  aspect-ratio: 3 / 2;
}
.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.82;
  transition: opacity 0.5s var(--ease), transform 0.6s var(--ease);
}
.gallery__item:hover img,
.gallery__item:focus-visible img {
  opacity: 1;
  transform: scale(1.03);
}
.gallery__item:focus-visible {
  outline: 1px solid var(--fg-soft);
  outline-offset: 2px;
}

/* ---------- Lightbox ---------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(var(--bg-rgb), 0.96);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s var(--ease), visibility 0s linear 0.35s;
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.35s var(--ease), visibility 0s;
}

/* The photograph has two sizes and nothing in between: fitted to
   the window, or its own full size. The stage holds it centred at
   the fitted size and becomes the thing you scroll once the
   photograph is bigger than the window. "safe" keeps the centring
   from pushing the top and left edges out of reach when it is. */
.lightbox__stage {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 3rem);
  overflow: hidden;
  overscroll-behavior: contain;
}
.lightbox.is-zoomed .lightbox__stage {
  align-items: safe center;
  justify-content: safe center;
  overflow: auto;
  cursor: grab;
}
.lightbox.is-panning .lightbox__stage {
  cursor: grabbing;
}

.lightbox__img {
  flex: 0 0 auto;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  cursor: zoom-in;
  -webkit-user-select: none;
  user-select: none;
}
.lightbox.is-zoomed .lightbox__img {
  max-width: none;
  max-height: none;
  cursor: inherit;   /* the stage is what is grabbed and scrolled */
}

.lightbox__btn {
  position: absolute;
  z-index: 1;   /* above the stage, which fills the lightbox */
  appearance: none;
  border: 0;
  padding: 0.9rem;
  background: transparent;
  color: var(--fg);
  opacity: 0.55;
  cursor: pointer;
  line-height: 0;
  transition: opacity 0.3s var(--ease);
}
.lightbox__btn:hover,
.lightbox__btn:focus-visible {
  opacity: 1;
}
.lightbox__btn:focus-visible {
  outline: 1px solid var(--fg-soft);
  outline-offset: 2px;
}
.lightbox__btn svg {
  width: 1.4rem;
  height: 1.4rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
}
.lightbox__close { top: clamp(0.5rem, 2vw, 1.25rem); right: clamp(0.5rem, 2vw, 1.25rem); }
.lightbox__prev  { left: clamp(0.25rem, 1.5vw, 1rem); top: 50%; transform: translateY(-50%); }
.lightbox__next  { right: clamp(0.25rem, 1.5vw, 1rem); top: 50%; transform: translateY(-50%); }

.lightbox__count {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: clamp(0.75rem, 2.5vw, 1.5rem);
  transform: translateX(-50%);
  padding: 0.35rem 0.7rem;
  border-radius: 2px;
  background: rgba(var(--bg-rgb), 0.7);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--fg-muted);
  pointer-events: none;
}

/* ---------- Wayfinder navigation ----------
   Fixed, bottom-right. Collapsed to three dots for the three
   chapters; opens on hover, focus, or tap. */

.wayfinder {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.75rem;
}

.wayfinder__toggle {
  appearance: none;
  border: 0;
  margin: 0;
  padding: 0.6rem;
  background: transparent;
  color: inherit;
  cursor: pointer;
  border-radius: 0;
}
.wayfinder__toggle:focus-visible {
  outline: 1px solid var(--fg-soft);
  outline-offset: 2px;
}

.wayfinder__dots {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.wayfinder__dots i {
  display: block;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--fg);
  opacity: 0.3;
  transition: opacity 0.4s var(--ease);
}
.wayfinder__dots i.is-current {
  opacity: 1;
}

.wayfinder__list {
  list-style: none;
  padding: 0.75rem 0.9rem;
  margin: 0;
  text-align: right;
  font-size: 0.8125rem;
  line-height: 1.5;
  background: rgba(var(--bg-rgb), 0.82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0s linear 0.35s;
}
.wayfinder:hover .wayfinder__list,
.wayfinder:focus-within .wayfinder__list,
.wayfinder.is-open .wayfinder__list {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease), visibility 0s;
}

.wayfinder__list li + li {
  margin-top: 0.35rem;
}
.wayfinder__list a {
  display: inline-block;
  padding: 0.15rem 0;
  color: var(--fg);
  opacity: 0.5;
  transition: opacity 0.3s var(--ease);
}
.wayfinder__list a:hover,
.wayfinder__list a:focus-visible,
.wayfinder__list a.is-current {
  opacity: 1;
}
.wayfinder__list a:focus-visible {
  outline: 1px solid var(--fg-soft);
  outline-offset: 3px;
}

/* ---------- Narrow screens ---------- */

@media (max-width: 899px) {
  .hero__text {
    padding-bottom: 18vh;
  }
  .chapter__images {
    padding: 8vh 0 10vh;
  }
  .pic--column,
  .pic--pair,
  .pic--line {
    width: auto;
    margin: 0 var(--gutter) 12vh;
  }
  .pic--portrait {
    display: flex;
  }
  .pic--portrait .pic__inner {
    width: 100%;
    align-items: center;
  }
  .pic--portrait .pic__img {
    width: auto;
    max-width: 100%;
    height: 68vh;
  }
  .stack .pic--column,
  .stack .pic--column:nth-child(even of .pic--column),
  .stack .pic--portrait,
  .stack .pic--portrait:nth-child(even of .pic--column),
  .stack .pic--pair,
  .stack .pic--line {
    left: var(--gutter);
    right: var(--gutter);
    width: auto;
    min-height: 0;
  }
  .stack .pic--portrait {
    display: flex;
  }
  .stack .pic--bleed-portrait {
    left: 0;
    right: 0;
    width: auto;
    display: flex;
  }
  .fig__pair {
    flex-direction: column;
    height: auto;
    width: 100%;
  }
  .fig__pair .pic__img {
    width: 100%;
    height: auto;
    max-height: 40vh;
    object-fit: contain;
  }
  .fig__divider {
    flex-basis: 1px;
    height: 1px;
    width: 100%;
    margin: clamp(1rem, 4vw, 2rem) 0;
  }
  .pic--line {
    min-height: 60vh;
    padding: 0;
  }
  .fig__corner {
    right: 0;
    bottom: 8vh;
    max-width: none;
    padding: 1.4rem var(--gutter);
    background: rgba(var(--bg-rgb), 0.62);
    -webkit-mask-image: none;
    mask-image: none;
  }
  /* Where the journal passes over them, captions and the set-in
     line sit on a small dark plate so both stay readable. */
  .stack .pic--column figcaption,
  .stack .pic--line .fulltext__line {
    padding: 0.6rem 0.8rem;
    background: rgba(var(--bg-rgb), 0.72);
  }
  .stack .pic--column figcaption {
    margin-top: 1rem;
    max-width: 100%;
  }
  .stack .pic--column figcaption::before {
    display: none;
  }

  /* The journal reads in the lower part of the screen, on a
     darkening that fades upward into the photographs. */
  .stack .notes {
    left: 0;
    right: 0;
    width: auto;
  }
  .stack .notes__scrim {
    background: linear-gradient(
      to bottom,
      rgba(var(--bg-rgb), 0) 0%,
      rgba(var(--bg-rgb), 0.36) 16%,
      rgba(var(--bg-rgb), 0.76) 30%,
      rgba(var(--bg-rgb), 0.86) 50%,
      rgba(var(--bg-rgb), 0.9) 100%
    );
    -webkit-mask-image: none;
    mask-image: none;
  }
  .stack .notes__scroll {
    top: 30vh;
    left: 0;
    right: 0;
    width: auto;
    padding: 6vh var(--gutter) 8vh;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 9%, #000 90%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #000 9%, #000 90%, transparent 100%);
  }
  .stack .notes__text {
    font-size: 1rem;
  }

  .gallery__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) and (max-width: 1279px) {
  .gallery__grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 479px) {
  .gallery__grid {
    grid-template-columns: 1fr;
  }
}

/* Touch devices have no hover; the toggle handles opening. */
@media (hover: none) {
  .wayfinder:hover:not(.is-open) .wayfinder__list {
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
  }
}

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .js .hero__text {
    animation: none;
  }
  .scroll-cue span {
    animation: none;
    transform: translateY(150%);
  }
  .wayfinder__list,
  .wayfinder__dots i,
  .wayfinder__list a,
  .gallery__item img,
  .lightbox,
  .lightbox__btn {
    transition: none;
  }
  .gallery__item:hover img,
  .gallery__item:focus-visible img {
    transform: none;
  }
}
