:root {
  --bg: #f8f3ec;
  --paper: #fffaf3;
  --ink: #1f1b18;
  --muted: #766c63;
  --line: rgba(31,27,24,.12);
  --accent: #9b5f44;
  --soft: #eadccc;
  --glow: #b9776a; /* warm dusty pink-brown — the Travel Globe's visited-location glow (rgb(185, 119, 106)) */
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: 'Inter', 'Noto Sans SC', sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.7;
}

.grain {
  pointer-events: none;
  position: fixed;
  inset: 0;
  opacity: .2;
  background-image: radial-gradient(#6d5b4c 0.5px, transparent 0.5px);
  background-size: 18px 18px;
  z-index: 10;
}

.nav {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  padding: 22px 7vw;
  backdrop-filter: blur(16px);
  background: rgba(248,243,236,.78);
  border-bottom: 1px solid var(--line);
}

/* Was "justify-content: space-between" with exactly two children
   (logo, nav-links). Now that the music toggle also lives in this
   same header on desktop (immediately after the nav links), space-
   between would spread the two apart instead of keeping them grouped
   tightly on the right — so instead the header just flows left-to-
   right, and <nav> gets pushed flush right with an auto margin.
   Visually this reproduces the original space-between result exactly
   for logo/nav — nothing about their positions actually changes. On
   mobile the music toggle reverts to its own fixed bottom-left
   position (see "AMBIENT MUSIC BUTTON" below) and is no longer part
   of this flex row at all, so nothing here needs a mobile-specific
   handoff for it. */
.nav nav {
  margin-left: auto;
}

.logo{
    width:58px;
    height:58px;
    display:flex;
    align-items:center;
    justify-content:center;
    text-decoration:none;
}
.logo img{
    width:100%;
    height:100%;
    object-fit:contain;
}
.nav a {
  margin-left: 24px;
  color: var(--ink);
  text-decoration: none;
  font-size: 14px;
}


/* ========================================
   MOBILE SITE MENU
   A hamburger toggle (top-right, mobile only) that opens a quiet
   full-screen index of every section on the page. The sticky header
   itself stays on top of the overlay (rather than being covered by
   it) so the toggle — morphed into an × — remains reachable to close
   it again. Explore's four destinations (Essays, Field Notes, Map,
   Gallery) are nested underneath it as smaller, indented rows, so the
   hierarchy of the page reads at a glance without needing a
   click-to-expand accordion.
======================================== */

.nav-menu-toggle {
  display: none;

  width: 26px;
  height: 16px;
  padding: 0;

  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;

  background: none;
  border: none;
  cursor: pointer;

  -webkit-tap-highlight-color: transparent;
}

.nav-menu-toggle-bar {
  display: block;
  width: 100%;
  height: 1.5px;

  background: var(--ink);

  transition:
    transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.3s ease;
}

.nav-menu-toggle[aria-expanded="true"] .nav-menu-toggle-bar:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}

.nav-menu-toggle[aria-expanded="true"] .nav-menu-toggle-bar:nth-child(2) {
  opacity: 0;
}

.nav-menu-toggle[aria-expanded="true"] .nav-menu-toggle-bar:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}

.site-menu {
  position: fixed;
  inset: 0;
  z-index: 4;

  display: none;
  flex-direction: column;

  padding-top: 102px;

  background: rgba(248, 243, 236, 0.97);
  backdrop-filter: blur(20px);

  opacity: 0;
  visibility: hidden;
  pointer-events: none;

  transition:
    opacity 0.45s ease,
    visibility 0s linear 0.45s;
}

.site-menu[aria-hidden="false"] {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;

  transition:
    opacity 0.45s ease,
    visibility 0s linear 0s;
}

.site-menu-list {
  flex: 1;

  display: flex;
  flex-direction: column;
  justify-content: center;

  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  padding: 0 8vw 40px;
}

.site-menu-item {
  position: relative;
  z-index: 1;

  display: flex;
  align-items: center;
  gap: 16px;

  padding: 15px 0;

  color: var(--ink);
  text-decoration: none;

  border-bottom: 1px solid var(--line);

  opacity: 0;
  transform: translateY(14px);

  transition:
    opacity 0.5s ease,
    transform 0.5s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.3s ease;
}

.site-menu-number {
  flex-shrink: 0;
  width: 30px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  letter-spacing: 0.14em;

  opacity: 0.55;
}

.site-menu-title {
  flex: 1;
  min-width: 0;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(26px, 7vw, 32px);
  font-weight: 500;
}

.site-menu-arrow {
  flex-shrink: 0;
  width: 17px;
  height: 17px;

  color: var(--accent);
  opacity: 0.5;

  transition:
    transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.3s ease;
}

.site-menu-item:active .site-menu-title,
.site-menu-item:hover .site-menu-title {
  color: var(--accent);
}

.site-menu-item:active .site-menu-arrow,
.site-menu-item:hover .site-menu-arrow {
  opacity: 1;
  transform: translate(4px, -4px) rotate(8deg);
}


/* Explore's sub-destinations — quieter, indented, no number/arrow */

.site-menu-item--sub {
  padding: 10px 0 10px 46px;

  border-bottom-color: transparent;
}

.site-menu-item--sub .site-menu-title {
  font-size: clamp(17px, 4.4vw, 19px);
  font-weight: 400;

  color: var(--muted);
}

.site-menu-item--sub:active .site-menu-title,
.site-menu-item--sub:hover .site-menu-title {
  color: var(--accent);
}

.site-menu-item:last-child {
  border-bottom: none;
}


/* Staggered reveal as the menu opens */

.site-menu[aria-hidden="false"] .site-menu-item {
  opacity: 1;
  transform: translateY(0);
}

.site-menu-item:nth-child(1)  { transition-delay: 0.04s; }
.site-menu-item:nth-child(2)  { transition-delay: 0.08s; }
.site-menu-item:nth-child(3)  { transition-delay: 0.11s; }
.site-menu-item:nth-child(4)  { transition-delay: 0.14s; }
.site-menu-item:nth-child(5)  { transition-delay: 0.17s; }
.site-menu-item:nth-child(6)  { transition-delay: 0.2s; }
.site-menu-item:nth-child(7)  { transition-delay: 0.23s; }
.site-menu-item:nth-child(8)  { transition-delay: 0.26s; }
.site-menu-item:nth-child(9)  { transition-delay: 0.29s; }

html.site-menu-open,
html.site-menu-open body {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .nav-menu-toggle-bar,
  .site-menu,
  .site-menu-item,
  .site-menu-arrow {
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
}

@media (max-width: 760px) {
  .nav-menu-toggle {
    display: flex;
    /* At this width <nav> is hidden and the music toggle has moved
       out to <body> (see audio.js), so the hamburger is left as the
       only item after the logo in the header's flex row — without
       this it just sits flush-left next to the logo instead of in
       its usual top-right corner. */
    margin-left: auto;
  }

  .site-menu {
    display: flex;
  }
}

main { padding: 0 7vw; }
.hero {
  min-height: 82vh;
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  align-items: center;
  gap: 48px;
  padding: 70px 0 40px;

  /* Setting only overflow-x here is a classic CSS trap: per spec, if
     one axis computes to something other than "visible" while the
     other computes to "visible", the "visible" one is FORCED to
     "auto" instead — and critically, this substitution happens
     whether that axis was left unset or set to "visible" explicitly.
     (A first attempt at this fix wrote `overflow-y: visible` here,
     which looks like it should opt out — it doesn't; the spec still
     silently promotes it to auto, because overflow-x is still
     non-visible.) .hero quietly became its own independently-
     scrollable box (min-height: 82vh, plus .hero-right::before's
     glow bleeding further via inset: -6%, was enough to overflow it
     vertically) — the second, ugly browser-default scrollbar that
     showed up hovering over the photo, confirmed by temporarily
     outlining the surrounding boxes and seeing exactly where it sat.
     The only way to actually get no scrollbar is for *neither* axis
     to compute to "visible" — so overflow-y: hidden below, matching
     overflow-x, clips the glow's bleed on both axes instead of just
     one. The glow is a soft, blurred, symmetric shape, so losing a
     sliver of its vertical bleed isn't visually noticeable. */
  overflow: hidden;
}

.hero-left {
    position: relative;
    z-index: 2;
    padding-top: 55px;
}

.hero-left {
    padding-left: 28px;
}

.hero-right {
  position: relative;
  min-height: 700px;
  margin-right: -5vw;
}

.handwriting {
  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-style: italic;
  font-size: 26px;
  font-weight: 500;
  color: var(--accent);
  opacity: 0.75;
  letter-spacing: 0.02em;
  margin-bottom: 34px;
}

.handwriting{
    position:relative;
    top:20px;
}

.hero h1 {
  font-size: clamp(68px, 7.6vw, 104px);
  line-height: 0.88;
  max-width: 520px;
}

.hero h1 em {
  display: block;
  font-style: italic;
  font-weight: 500;
}

.short-line {
  width: 54px;
  height: 1px;
  background: var(--accent);
  margin: 32px 0 26px;
}

.hero-text {
  max-width: 420px;
  color: var(--muted);
  font-size: 17px;
  line-height: 1.7;
}

.hero-copy {
    max-width: 180px;
    line-height: 1.8;
}

.hero-photo {
  position: absolute;
  inset: 0;
  border-radius: 0 0 0 120px;

  background-image:
    linear-gradient(rgba(248,243,236,.12), rgba(248,243,236,.08)),
    url("images/hero.jpeg");

  /* `cover` + `no-repeat` — the same fix already applied under the
     mobile breakpoint below (see the "Hero mobile" comment there).
     The old `background-size: 100%` only sets the image's *width*;
     whenever the box's actual height/width ratio makes the image
     render shorter than the box, the browser tiles it to fill the
     rest — a second, slightly offset copy starting right where the
     first one ends, which shows up as a thin seam (the "重影"
     ghosting) right at that repeat boundary. `cover` guarantees the
     image always fills the box on both axes with a single copy, so
     there's no seam to tile in the first place, at any viewport
     width — not just below the mobile breakpoint. */
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center 45%;
}

/* ========================================
   HERO ENTRANCE — "the page breathes in"
   Pure CSS, no loading screen, no JS: the
   page is already fully laid out on first
   paint, and these elements simply ease
   into their resting state via animation-
   delay. Order: photo → handwriting → body
   copy → title (deliberately a touch slower
   and heavier than the copy) → line → Begin
   button, which settles in last, like a
   held breath finishing. A faint ambient
   glow behind the photo and a near-
   imperceptible drift on the grain texture
   keep things quietly alive afterwards,
   rather than the page going still the
   moment the entrance finishes.
======================================== */

.hero-photo {
  opacity: 0;
  animation: hero-photo-in .85s cubic-bezier(.16,1,.3,1) forwards;
}

.hero-right::before {
  content: "";
  position: absolute;
  inset: -6%;
  border-radius: 0 0 0 140px;
  background: radial-gradient(circle at 60% 35%, rgba(185,119,106,.4), rgba(185,119,106,0) 65%);
  filter: blur(40px);
  opacity: 0;
  pointer-events: none;
  animation:
    hero-glow-in .9s ease-out .1s forwards,
    hero-glow-breathe 9s ease-in-out 1s infinite;
}

.handwriting {
  opacity: 0;
  animation: hero-rise-in .5s ease-out .05s forwards;
}

.hero-copy {
  opacity: 0;
  animation: hero-rise-in .5s ease-out .12s forwards;
}

.hero h1 {
  opacity: 0;
  animation: hero-rise-in-title .65s cubic-bezier(.19,1,.22,1) .2s forwards;
}

.short-line {
  opacity: 0;
  transform-origin: left center;
  animation: hero-line-in .5s ease-out .5s forwards;
}

.begin-button {
  opacity: 0;
  animation: hero-rise-in .5s ease-out .62s forwards;
}

@keyframes hero-photo-in {
  from { opacity: 0; transform: scale(1.035); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes hero-glow-in {
  from { opacity: 0; }
  to   { opacity: .22; }
}

@keyframes hero-glow-breathe {
  0%, 100% { opacity: .16; transform: scale(1); }
  50%      { opacity: .3; transform: scale(1.04); }
}

@keyframes hero-rise-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes hero-rise-in-title {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes hero-line-in {
  from { opacity: 0; transform: scaleX(0); }
  to   { opacity: 1; transform: scaleX(1); }
}

@keyframes grain-drift {
  0%, 100% { background-position: 0 0; }
  50%      { background-position: 7px 11px; }
}

.grain {
  animation: grain-drift 48s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero-photo,
  .hero-right::before,
  .handwriting,
  .hero-copy,
  .hero h1,
  .short-line,
  .begin-button,
  .grain {
    animation: none !important;
  }

  .hero-photo,
  .handwriting,
  .hero-copy,
  .hero h1,
  .short-line,
  .begin-button {
    opacity: 1 !important;
    transform: none !important;
  }

  .hero-right::before {
    opacity: .22;
  }
}

.eyebrow, .section-label {
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
}
h1, h2, h3 {
  font-family: 'Cormorant Garamond', 'Noto Serif SC', serif;
  line-height: 1.05;
  margin: 0;
}
h1 {
  font-size: clamp(72px, 12vw, 150px);
  letter-spacing: -0.05em;
}
h2 { font-size: clamp(40px, 6vw, 76px); letter-spacing: -0.035em; }
h3 { font-size: 28px; }
.hero-text {
  max-width: 720px;
  font-size: clamp(19px, 2vw, 25px);
  color: var(--muted);
}
.button {
    display: inline-flex;
    align-items: center;
    gap: 8px;

    padding: 0;
    margin-top: 36px;

    font-size: 17px;
    font-weight: 500;
    letter-spacing: 0.03em;

    text-decoration: none;

    color: var(--accent);

    transition: all .35s ease;
}
.primary{
    background:none;
    color:var(--accent);

    border:none;

    border-bottom:1px solid rgba(153,113,84,.35);
    padding-bottom:6px;
}
.secondary{
    display:none;
}
.button:hover{
    gap:16px;
    color:#7f543b;
}

.primary:hover{
    border-bottom-color:#7f543b;
}

/* Explore */

.explore-section {
  display: block;

  padding: 120px 0 110px;

  border-top: 1px solid var(--line);
}


/* Explore introduction */

.explore-intro {
  max-width: 820px;
  min-height: calc(100vh - 190px);

  display: flex;
  flex-direction: column;
  justify-content: center;

  padding-bottom: 12vh;
  margin-bottom: 0;
}

.explore-intro h2 {
  max-width: 780px;
  margin-top: 24px;

  font-size: clamp(58px, 6vw, 92px);
  line-height: 0.96;
}

.explore-intro h2 em {
  color: var(--accent);
  font-weight: 500;
}

.explore-copy {
  max-width: 620px;
  margin: 38px 0 0;

  color: var(--muted);

  font-size: 16px;
  line-height: 1.8;
}


/* Explore list */

.explore-list {
  border-top: 1px solid rgba(31, 27, 24, 0.3);
}

.explore-item {
  position: relative;

  display: grid;
  grid-template-columns: 54px minmax(260px, 1fr) 260px 40px;
  align-items: center;
  gap: 24px;

  min-height: 148px;
  padding: 0px 8px;

  color: var(--ink);
  text-decoration: none;

  border-bottom: 1px solid var(--line);

  overflow: hidden;

  transition:
    padding 0.4s ease,
    background-color 0.4s ease,
    color 0.4s ease;
}

.explore-item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;

  background:
    radial-gradient(
      ellipse at 28% 50%,
      rgba(155, 95, 68, 0.09) 0%,
      rgba(181, 135, 102, 0.045) 38%,
      transparent 72%
    ),
    linear-gradient(
      90deg,
      rgba(255, 250, 243, 0.28),
      rgba(234, 220, 204, 0.12),
      transparent 82%
    );

  opacity: 0;
  transition: opacity 0.55s ease;
}

.explore-item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;

  background:
    linear-gradient(
      90deg,
      rgba(255, 250, 243, 0.62) 0%,
      rgba(247, 238, 228, 0.48) 48%,
      rgba(248, 243, 236, 0.18) 100%
    );

  opacity: 0;
  transition: opacity 0.45s ease;
}

.explore-item:hover::before {
  opacity: 1;
}

/* Number */

.explore-number {
  position: relative;
  z-index: 2;
  align-self: start;

  padding-top: 18px;

  color: var(--accent);

  font-size: 11px;
  letter-spacing: 0.14em;

  opacity: 0.48;

  transition:
    opacity 0.4s ease,
    transform 0.4s ease,
    letter-spacing 0.4s ease;
}

.explore-item:hover .explore-number {
  opacity: 1;
  transform: translateY(-3px);
  letter-spacing: 0.22em;
}


/* Title */

.explore-title {
  position: relative;
  z-index: 2;

  transition: transform 0.4s ease;
}

.explore-title h3 {
  font-size: clamp(36px, 3.3vw, 52px);
  font-weight: 500;

  transition:
    letter-spacing 0.45s ease,
    transform 0.45s ease;
}

.explore-item:hover .explore-title h3 {
  letter-spacing: 0.018em;
  transform: translateY(-2px);
}

.explore-title p {
  margin: 8px 0 0;

  color: var(--muted);

  font-size: 14px;

  transition: color 0.4s ease;
}


/* Preview image */

.explore-preview {
  position: relative;
  z-index: 2;
  align-self: stretch;

  width: 300px;
  height: 100%;
  min-height: 148px;

  overflow: visible;

  opacity: 0;
  transform:
    translateX(46px)
    translateY(4px)
    rotate(-1.5deg)
    scale(0.96);

  transition:
    opacity 0.5s ease,
    transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
}

.explore-preview img {
  position: absolute;
  top: 0;
  right: 0;

  display: block;

  width: auto;
  max-width: none;
  height: 100%;

  object-fit: contain;

  filter: saturate(0.72) contrast(0.94);

  transition:
    transform 0.7s ease,
    filter 0.5s ease;
}


/* Arrow */

.explore-arrow {
  position: relative;
  z-index: 2;

  justify-self: end;

  display: block;
  width: 21px;
  height: 21px;

  color: var(--accent);

  transition: transform 0.4s ease;
}

.explore-arrow svg,
.essay-arrow svg {
  display: block;
  width: 100%;
  height: 100%;
}


/* Hover */
.explore-item:hover {
  padding-left: 18px;
  padding-right: 18px;

  color: var(--accent);

  background: rgba(234, 220, 204, 0.22);
}

.explore-item:hover .explore-title {
  transform: translateX(6px);
}

.explore-item:hover .explore-preview {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.explore-item:hover .explore-preview img {
  transform: scale(1.05);

  filter: saturate(0.9) contrast(0.98);
}

.explore-item:hover .explore-arrow {
  transform: translate(6px, -6px) rotate(8deg);
}

/* 进入 Explore 后，在用户真正移动鼠标前强制保持默认状态 */
.explore-section.explore-entering .explore-item:hover {
  padding-left: 8px;
  padding-right: 8px;
  color: var(--ink);
  background: transparent;
}

.explore-section.explore-entering .explore-item:hover::before {
  opacity: 0;
}

.explore-section.explore-entering .explore-item:hover .explore-title {
  transform: none;
}

.explore-section.explore-entering .explore-item:hover .explore-title h3 {
  letter-spacing: normal;
  transform: none;
}

.explore-section.explore-entering .explore-item:hover .explore-number {
  opacity: 0.48;
  transform: none;
  letter-spacing: 0.14em;
}

.explore-section.explore-entering .explore-item:hover .explore-preview {
  opacity: 0;
  transform:
    translateX(46px)
    translateY(4px)
    rotate(-1.5deg)
    scale(0.96);
}

.explore-section.explore-entering .explore-item:hover .explore-preview img {
  transform: none;
  filter: saturate(0.72) contrast(0.94);
}

.explore-section.explore-entering .explore-item:hover .explore-arrow {
  transform: none;
}

/* ========================================
   HERO → EXPLORE TRANSITION
======================================== */

#explore {
  scroll-margin-top: 86px;
}

/* ----------------------------------------
   INTRO REVEAL
---------------------------------------- */
.explore-reveal {
  opacity: 0;
  visibility: hidden;

  transform: translate3d(0, 18px, 0);

  will-change: opacity, transform;

  transition:
    opacity 1.45s cubic-bezier(0.22, 1, 0.36, 1),
    transform 1.45s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 1.15s;
}

.explore-section.intro-reset .explore-reveal {
  opacity: 0 !important;
  visibility: hidden !important;
  transform: translate3d(0, 10px, 0) !important;

  transition: none !important;
}

.explore-section.intro-visible .explore-reveal {
  opacity: 1;
  visibility: visible;

  transform: translate3d(0, 0, 0);

  transition:
    opacity 1.15s cubic-bezier(0.16, 1, 0.3, 1),
    transform 1.15s cubic-bezier(0.16, 1, 0.3, 1),
    visibility 0s;
}

.explore-section.intro-visible .explore-reveal-1 {
  transition-delay: 0.04s;
}

.explore-section.intro-visible .explore-reveal-2 {
  transition-delay: 0.14s;
}

.explore-section.intro-visible .explore-reveal-3 {
  transition-delay: 0.32s;
}

/* ----------------------------------------
   LIST REVEAL
---------------------------------------- */

.explore-item {
  opacity: 0;
  transform: translate3d(0, 38px, 0);

  will-change: opacity, transform;

  transition:
    opacity 1.15s cubic-bezier(0.16, 1, 0.3, 1),
    transform 1.15s cubic-bezier(0.16, 1, 0.3, 1),
    padding 0.4s ease,
    background-color 0.4s ease,
    color 0.4s ease;
}

.explore-item.item-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}


/* ----------------------------------------
   LOCK ACCIDENTAL HOVER
---------------------------------------- */

.explore-section.explore-entering .explore-item {
  pointer-events: none;
}

.explore-section.explore-entering .explore-item:hover {
  padding-left: 8px;
  padding-right: 8px;

  color: var(--ink);
  background: transparent;
}

.explore-section.explore-entering .explore-item:hover::before {
  opacity: 0;
}

.explore-section.explore-entering .explore-item:hover .explore-title {
  transform: none;
}

.explore-section.explore-entering .explore-item:hover .explore-title h3 {
  letter-spacing: normal;
  transform: none;
}

.explore-section.explore-entering .explore-item:hover .explore-number {
  opacity: 0.48;
  transform: none;
  letter-spacing: 0.14em;
}

.explore-section.explore-entering .explore-item:hover .explore-preview {
  opacity: 0;
  filter: blur(2px);

  transform:
    translateX(46px)
    translateY(4px)
    rotate(-1.5deg)
    scale(0.96);
}

.explore-section.explore-entering .explore-item:hover .explore-preview img {
  transform: none;
  filter: saturate(0.72) contrast(0.94);
}

.explore-section.explore-entering .explore-item:hover .explore-arrow {
  transform: none;
}


/* ----------------------------------------
   PREVIEW IMAGE REVEAL
---------------------------------------- */

.explore-preview {
  filter: blur(2px);

  transition:
    opacity 0.65s ease 0.06s,
    transform 0.76s cubic-bezier(0.22, 1, 0.36, 1),
    filter 0.65s ease 0.06s;
}

.explore-item:hover .explore-preview {
  opacity: 1;
  filter: blur(0);

  transform:
    translateX(0)
    translateY(0)
    rotate(0)
    scale(1);
}


/* ----------------------------------------
   ACCESSIBILITY
---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .explore-reveal,
  .explore-item,
  .explore-preview {
    transition-duration: 0.01ms;
    transition-delay: 0s;
  }
}

/* ========================================
   SCROLL REVEAL — page-wide
   Generalises the Explore section's own fade
   + gentle-rise (above) to every section below
   it — Essays, Field Notes, Map, Gallery,
   Projects, About Me, Contact — so scrolling
   down never pops content in; each piece
   eases into place once, the first time it
   crosses into view (see script.js "SCROLL
   REVEAL"). `--reveal-delay` lets a handful of
   side-by-side elements (a heading next to its
   copy, three gallery panels, two project
   cards) stagger slightly rather than arriving
   in a single flat beat — set per-element
   below, right next to what it's staggering.
   Reduced-motion users still get the reveal,
   just instantly, matching the Explore
   section's own convention above.
======================================== */

.reveal-up {
  opacity: 0;
  transform: translate3d(0, 26px, 0);

  will-change: opacity, transform;

  transition:
    opacity 1.1s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
    transform 1.1s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s);
}

.reveal-up.is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.reveal-d1 { --reveal-delay: 0.05s; }
.reveal-d2 { --reveal-delay: 0.15s; }
.reveal-d3 { --reveal-delay: 0.27s; }
.reveal-d4 { --reveal-delay: 0.38s; }

@media (prefers-reduced-motion: reduce) {
  .reveal-up {
    transition-duration: 0.01ms;
  }
}

.section, .split-section, .contact {
  padding: 90px 0;
  border-top: 1px solid var(--line);
}
.split-section {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: 60px;
}
.split-section p:last-child {
  font-size: 22px;
  color: var(--muted);
  margin: 40px 0 0;
}
.section-heading { margin-bottom: 34px; }

.map-card {
  display: grid;
  grid-template-columns: 1.35fr .85fr;
  min-height: 460px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 34px;
  overflow: hidden;
}


/* ----------------------------------------
   GLOBE STAGE — a quiet, hand-drawn-feeling 3D globe rendered on
   canvas by globe.js (paper-toned sphere + faint graticule; no
   continents, no photographic texture — an atlas, not a map service).
   The ambient background behind the sphere echoes the old map's warm
   radial wash so the section keeps the same overall temperature.
---------------------------------------- */

.globe-stage {
  position: relative;
  overflow: hidden;
  cursor: grab;
  touch-action: none;

  /* Dragging/pinching happens directly on this box — without this,
     a fast drag on desktop starts highlighting text behind the
     canvas, and a press-drag on mobile can trigger the native
     callout/selection menu. Nothing inside is selectable text
     anyway (canvas + buttons), so this is safe everywhere. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;

  background:
    radial-gradient(circle at 50% 46%, rgba(234, 220, 204, 0.7) 0%, transparent 55%),
    linear-gradient(160deg, #f9efe3, #eee0d0);
}

.globe-stage:active {
  cursor: grabbing;
}

.globe-canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* Hover warmth — a soft glow-tinted wash that fades in while any
   marker is hovered/focused, toggled by globe.js via .is-warm. */
.globe-stage::after {
  content: "";
  position: absolute;
  inset: 0;

  background: radial-gradient(circle at 50% 50%, rgba(185, 119, 106, 0.14), transparent 68%);

  opacity: 0;
  transition: opacity 0.7s ease;
  pointer-events: none;
}

.globe-stage.is-warm::after {
  opacity: 1;
}


/* ----------------------------------------
   GLOBE MARKERS — small dots, not labelled pins: a name only
   surfaces on hover/focus/selection, so eighteen real (sometimes
   geographically close) places stay legible rather than cluttered.
   Position is set every animation frame by globe.js via inline
   transform, matching the sphere's current rotation.
---------------------------------------- */

.globe-marker {
  position: absolute;
  top: 0;
  left: 0;
  width: 26px;
  height: 26px;

  display: flex;
  align-items: center;
  justify-content: center;

  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  will-change: transform;
}

.globe-marker-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--glow);
  box-shadow: 0 0 0 3px rgba(255, 250, 243, 0.75);

  transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease;
}

.globe-marker:hover .globe-marker-dot,
.globe-marker:focus-visible .globe-marker-dot {
  transform: scale(1.35);
}

.globe-marker:focus-visible {
  outline: none;
}

.globe-marker:focus-visible .globe-marker-dot {
  box-shadow: 0 0 0 3px rgba(255, 250, 243, 0.9), 0 0 0 5px rgba(185, 119, 106, 0.35);
}

/* Subtle glow on the locked selection — a warm dusty pink-brown
   shadow, not a pulsing effect; restraint over spectacle. */
.globe-marker.is-selected .globe-marker-dot {
  box-shadow: 0 0 0 3px rgba(255, 250, 243, 0.9), 0 0 14px rgba(185, 119, 106, 0.5);
}

.globe-marker-label {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(2px);

  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255, 250, 243, 0.92);
  border: 1px solid var(--line);
  backdrop-filter: blur(6px);

  color: var(--ink);
  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;

  opacity: 0;
  pointer-events: none;

  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.globe-marker:hover .globe-marker-label,
.globe-marker:focus-visible .globe-marker-label,
.globe-marker.is-selected .globe-marker-label {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}


/* ----------------------------------------
   NOTE PANEL
---------------------------------------- */

.map-note {
  display: flex;
  flex-direction: column;
  justify-content: center;

  padding: 50px;

  transition: opacity 0.35s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.map-note.is-fading {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
}

.map-note h3 {
  font-size: clamp(34px, 4vw, 50px);
}

/* Wraps the place name together with the prev/next arrows, so
   align-items: center vertically centers the arrows against the
   *visible text*, not against some guessed offset — this is what
   keeps their centerline genuinely on the same line as the name's,
   regardless of font metrics. Carries the top margin that used to
   live on h3 itself (moved here rather than left on h3, since a
   margin on a flex item would have thrown its own centering off). */
.map-note-heading {
  display: flex;
  align-items: center;
  gap: 14px;

  margin-top: 14px;
}

.map-note-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;

  width: 22px;
  height: 22px;
  padding: 0;

  background: none;
  border: none;

  color: var(--accent);
  opacity: 0.42;
  cursor: pointer;

  transition: opacity 0.35s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

.map-note-arrow svg {
  width: 18px;
  height: 18px;
}

.map-note-arrow:hover,
.map-note-arrow:focus-visible {
  opacity: 0.9;
}

.map-note-arrow--prev:hover {
  transform: translateX(-3px);
}

.map-note-arrow--next:hover {
  transform: translateX(3px);
}

.map-note-arrow:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
  border-radius: 3px;
}

.map-note-meta {
  margin: 8px 0 0;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 12px;
  letter-spacing: 0.04em;
}

.map-note p {
  margin: 20px 0 0;

  color: var(--muted);
  font-size: 18px;
}

.map-note .text-link {
  margin-top: 24px;
}

.text-link { color: var(--accent); text-decoration: none; font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .globe-marker-dot,
  .globe-marker-label,
  .map-note,
  .map-note-arrow {
    transition-duration: 0.01ms;
  }
}

/* ========================================
   PROJECTS
   Each shipped project (Envelope, Clinical
   Atlas, Feedback to Action) gets its own wide
   "feature" card — thumbnail plus a short pitch
   — framed as an object (bordered, inset image,
   on --paper) rather than full-bleed like the
   Gallery entrance, so Projects reads as its own
   quieter shelf rather than a copy of the
   Gallery. The card carries two links: "View
   live demo" is primary (a stretched-link
   overlay makes the whole card clickable to it),
   "View source" is a small, quiet secondary link
   to the GitHub repo — see the note above
   .project-feature-links for how the two
   coexist without nesting <a> inside <a>.
   Feature cards stack one per row (rather than
   side by side) so the list can grow to any
   number of shipped projects without the grid
   needing to change shape. The final row is a
   narrow, muted "still brewing" placeholder,
   centered and capped at a much smaller width
   than the feature cards above it — deliberately
   smaller, so the asymmetry itself signals
   "here's what's shipped, and here's what's
   next" rather than another full-width card. */

.projects-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;

  margin-top: 64px;
}

.project-feature {
  position: relative;

  display: grid;
  grid-template-columns: 1.05fr 1fr;
  align-items: stretch;

  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 28px;
  overflow: hidden;

  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.6s ease;
}

.project-feature:hover,
.project-feature:focus-within {
  transform: translateY(-4px);
  border-color: rgba(155, 95, 68, 0.32);
}

.project-feature-image {
  display: block;

  min-height: 300px;

  background: var(--bg);
}

.project-feature-image img {
  display: block;
  width: 100%;
  height: 100%;

  object-fit: contain;
  object-position: center;

  transform: scale(1);
  transition: transform 1s cubic-bezier(0.22, 1, 0.36, 1);
}

.project-feature:hover .project-feature-image img,
.project-feature:focus-within .project-feature-image img {
  transform: scale(1.03);
}

.project-feature-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;

  padding: 40px;
}

.project-feature-eyebrow {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;

  color: var(--accent);
}

.project-feature-title {
  font-size: clamp(28px, 2.6vw, 36px);
  font-weight: 500;
  line-height: 1.1;

  color: var(--ink);
}

.project-feature-tagline {
  max-width: 42ch;
  margin: 0;

  color: var(--muted);
  line-height: 1.65;
}

/* Two links, one card: "View live demo" is the primary action — a
   stretched-link overlay (.project-feature-stretched-link) makes the
   *whole card* clickable to it, same one-destination feel as the
   Gallery panels. "View source" stays a small, quiet secondary link
   sitting on top of that overlay (z-index 2) so it's still its own
   independent target, not swallowed by the stretch. */

.project-feature-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 20px;

  margin-top: 6px;
}

.project-feature-link {
  position: relative;
  z-index: 2;

  display: inline-flex;
  align-items: center;
  gap: 4px;

  font-size: 14px;
  font-weight: 600;

  text-decoration: none;
}

.project-feature-link--primary {
  color: var(--accent);
}

.project-feature-link--secondary {
  font-size: 13px;
  font-weight: 500;

  color: var(--muted);

  transition: color 0.4s ease;
}

.project-feature-link--secondary:hover,
.project-feature-link--secondary:focus-visible {
  color: var(--accent);
}

.project-feature-stretched-link {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.project-feature-link:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}

.project-teaser {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;

  max-width: 300px;
  margin: 0 auto;
  padding: 30px 20px;

  background: rgba(155, 95, 68, 0.05);
  border: 1px dashed var(--line);
  border-radius: 28px;

  text-align: center;
}

.project-teaser .project-animal {
  margin: 0;

  font-size: 13px;
  line-height: 1.3;

  color: var(--muted);
  opacity: 0.8;
}

.project-teaser h3 {
  font-size: 19px;
}

.project-teaser p {
  font-size: 13px;
  color: var(--muted);
}

/* Scroll reveal stagger — see "SCROLL REVEAL" further up for the
   shared .reveal-up recipe; .reveal-d2 (defined there) staggers the
   teaser card in just after the feature card. */

@media (max-width: 900px) {
  .project-feature {
    grid-template-columns: 1fr;
  }

  .project-feature-image {
    min-height: 220px;
  }

  .project-teaser {
    max-width: none;
    min-height: 160px;
  }
}

/* ========================================
   FIELD NOTES — SCATTERED ARCHIVE
======================================== */

.field-notes-section {
  overflow: hidden;
}

.field-notes-copy {
  max-width: 420px;
  margin: 18px 0 0;

  color: var(--muted);

  font-size: 15px;
  line-height: 1.8;
}


/* Horizontal row */

.field-notes-row {
  display: flex;
  gap: 30px;

  width: 100vw;
  margin-left: calc(-50vw + 50%);
  margin-top: 54px;
  padding: 10px 7vw 34px;

  overflow-x: auto;
  overflow-y: visible;

  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;

  scrollbar-width: thin;
  scrollbar-color: rgba(155, 95, 68, 0.28) transparent;
}

.field-notes-row::-webkit-scrollbar {
  height: 3px;
}

.field-notes-row::-webkit-scrollbar-track {
  background: transparent;
}

.field-notes-row::-webkit-scrollbar-thumb {
  background: rgba(155, 95, 68, 0.28);
  border-radius: 999px;
}


/* Card */

.field-note-card {
  position: relative;
  flex: 0 0 auto;

  display: flex;
  flex-direction: column;

  width: 258px;
  min-height: 232px;
  padding: 26px 26px 22px;

  color: var(--ink);
  text-decoration: none;

  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;

  box-shadow: 0 1px 0 rgba(31, 27, 24, 0.02);

  transform: translateY(0) rotate(0deg);

  transition:
    transform 0.5s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.5s ease,
    border-color 0.4s ease;
}

.field-note-card:nth-child(3n+1) { transform: rotate(-0.6deg); }
.field-note-card:nth-child(3n+2) { transform: rotate(0.5deg); }
.field-note-card:nth-child(3n)   { transform: rotate(-0.3deg); }

.field-note-card:hover,
.field-note-card:focus-visible {
  transform: translateY(-6px) rotate(0deg);

  border-color: rgba(155, 95, 68, 0.3);

  box-shadow:
    0 18px 34px rgba(31, 27, 24, 0.07),
    0 4px 10px rgba(31, 27, 24, 0.04);
}

.field-note-card:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}


/* Number */

.field-note-number {
  display: block;

  margin-bottom: 20px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;

  opacity: 0.55;

  transition: opacity 0.4s ease;
}

.field-note-card:hover .field-note-number {
  opacity: 0.9;
}


/* Title / hook crossfade */

.field-note-face {
  position: relative;
  display: grid;

  flex: 1;
  align-content: start;
}

.field-note-title,
.field-note-reveal {
  grid-area: 1 / 1;
}

.field-note-title {
  margin: 0;

  font-size: 25px;
  font-weight: 500;
  line-height: 1.22;

  transition:
    opacity 0.4s ease,
    transform 0.4s ease;
}

.field-note-reveal {
  display: flex;
  flex-direction: column;
  gap: 12px;

  opacity: 0;
  transform: translateY(6px);

  transition:
    opacity 0.45s ease,
    transform 0.45s ease;
}

.field-note-hook {
  margin: 0;

  color: #8d5942;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 21px;
  font-style: italic;
  font-weight: 500;
  line-height: 1.4;
}

.field-note-read {
  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.field-note-card:hover .field-note-title,
.field-note-card:focus-visible .field-note-title {
  opacity: 0;
  transform: translateY(-6px);
}

.field-note-card:hover .field-note-reveal,
.field-note-card:focus-visible .field-note-reveal {
  opacity: 1;
  transform: translateY(0);
}


/* Meta */

.field-note-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;

  margin-top: 20px;
  padding-top: 16px;

  border-top: 1px solid var(--line);
}

.field-note-tags,
.field-note-date {
  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.field-note-tags {
  color: var(--accent);
  opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
  .field-notes-row {
    scroll-behavior: auto;
  }

  .field-note-card,
  .field-note-title,
  .field-note-reveal {
    transition-duration: 0.01ms;
  }
}

@media (max-width: 760px) {
  .field-notes-row {
    gap: 18px;
    margin-top: 40px;
    padding: 8px 6vw 26px;
  }

  .field-note-card {
    width: 218px;
    min-height: 208px;
    padding: 22px 22px 18px;
  }

  .field-note-title {
    font-size: 22px;
  }

  .field-note-hook {
    font-size: 19px;
  }
}

/* ========================================
   ESSAYS — BOOK SPINE
======================================== */

.essays-section {
  padding-top: 140px;
  padding-bottom: 130px;
}


/* Essays introduction */

.essays-intro {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.55fr);
  align-items: end;
  gap: 72px;

  margin-bottom: 88px;
}

.essays-heading h2 {
  margin-top: 22px;

  font-size: clamp(58px, 6.2vw, 92px);
  line-height: 0.94;
}

.essays-heading h2 em {
  color: var(--accent);
  font-weight: 500;
}

.essays-intro-copy {
  max-width: 360px;
  margin: 0 0 8px;

  color: var(--muted);

  font-size: 15px;
  line-height: 1.85;
}


/* Shelf */

.essay-shelf {
  position: relative;

  border-top: 1px solid rgba(31, 27, 24, 0.28);
}


/* Individual book spine */

.essay-spine {
  position: relative;

  display: grid;
  grid-template-columns:
  34px
  minmax(310px, 1fr)
  minmax(260px, 360px)
  30px;

  align-items: center;
  gap: 28px;

  min-height: 132px;
  padding: 22px 12px 22px 18px;

  color: var(--ink);
  text-decoration: none;

  border-bottom: 1px solid var(--line);

  overflow: hidden;

  opacity: 0;
  transform: translateX(0);

  transition:
    opacity 1s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
    transform 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    padding 0.62s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.5s ease,
    box-shadow 0.55s ease;
}

/* Scroll reveal — opacity only (not the shared .reveal-up recipe),
   since this element's own `transform` is already spoken for by its
   hover slide-right above; animating both from the same property
   would fight each other. Staggered per spine via --reveal-delay,
   same mechanism as everywhere else — see "SCROLL REVEAL" above. */
.essay-spine.is-visible {
  opacity: 1;
}

.essay-spine:nth-of-type(2) { --reveal-delay: 0.12s; }
.essay-spine:nth-of-type(3) { --reveal-delay: 0.24s; }

@media (prefers-reduced-motion: reduce) {
  .essay-spine {
    transition-duration: 0.01ms;
  }
}


/* Book-spine line */

.essay-spine::after {
  content: "";

  position: absolute;
  left: 0;
  top: 18px;
  bottom: 18px;

  width: 2px;

  background: rgba(155, 95, 68, 0.25);

  transform: scaleY(0.72);
  transform-origin: center;

  transition:
    background-color 0.45s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}


/* Soft paper layer */

.essay-spine::before {
  content: "";

  position: absolute;
  inset: 0;
  z-index: 0;

  pointer-events: none;

  background:
    linear-gradient(
      90deg,
      rgba(255, 250, 243, 0.78) 0%,
      rgba(244, 232, 219, 0.42) 52%,
      rgba(248, 243, 236, 0.08) 100%
    );

  opacity: 0;

  transition: opacity 0.55s ease;
}


/* Keep all content above background */

.essay-dot,
.essay-title,
.essay-quote,
.essay-arrow {
  position: relative;
  z-index: 1;
}

/* Small shelf marker */

.essay-dot {
  align-self: center;
  justify-self: center;

  width: 6px;
  height: 6px;

  border-radius: 50%;

  background: var(--accent);

  opacity: 0.38;

  transform: scale(1);

  transition:
    opacity 0.45s ease,
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.45s ease;
}

/* Essay title */

.essay-title {
  min-width: 0;

  transition:
    transform 0.58s cubic-bezier(0.22, 1, 0.36, 1);
}

.essay-title h3 {
  margin: 0;

  font-size: clamp(29px, 2.8vw, 44px);
  font-weight: 500;
  line-height: 1;

  transition:
    color 0.45s ease,
    letter-spacing 0.5s ease;
}

.essay-type {
  display: block;

  margin-top: 12px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;

  transition:
    color 0.45s ease,
    transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}


/* Quote */

.essay-quote {
  max-width: 340px;
  margin: 0;

  color: var(--muted);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 18px;
  font-style: italic;
  line-height: 1.42;

  opacity: 0;
  transform: translateX(22px);

  transition:
    opacity 0.55s ease 0.04s,
    transform 0.68s cubic-bezier(0.22, 1, 0.36, 1);
}


/* Arrow */

.essay-arrow {
  justify-self: end;

  display: block;
  width: 19px;
  height: 19px;

  color: var(--accent);

  opacity: 0.38;

  transition:
    opacity 0.45s ease,
    transform 0.56s cubic-bezier(0.22, 1, 0.36, 1);
}


/* Hover — pull the book from the shelf */

.essay-spine:hover {
  transform: translateX(14px);

  padding-left: 26px;
  padding-right: 18px;

  background: rgba(255, 250, 243, 0.48);

  box-shadow:
    -14px 0 22px rgba(31, 27, 24, 0.045),
    0 13px 28px rgba(31, 27, 24, 0.035);
}

.essay-spine:hover::before {
  opacity: 1;
}

.essay-spine:hover::after {
  background: var(--accent);

  transform: scaleY(1);
}

.essay-spine:hover .essay-dot {
  opacity: 1;

  transform: scale(1.45);

  box-shadow:
    0 0 0 5px rgba(155, 95, 68, 0.08);
}

.essay-spine:hover .essay-title {
  transform: translateX(6px);
}

.essay-spine:hover .essay-title h3 {
  color: var(--accent);

  letter-spacing: 0.008em;
}

.essay-spine:hover .essay-type {
  color: var(--ink);

  transform: translateX(2px);
}

.essay-spine:hover .essay-quote {
  opacity: 1;

  transform: translateX(0);
}

.essay-spine:hover .essay-arrow {
  opacity: 1;

  transform: translate(5px, -5px) rotate(7deg);
}


/* Ending */

.essays-ending {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 18px;

  padding-top: 32px;
}

.essays-ending-line {
  width: 36px;
  height: 1px;

  background: rgba(155, 95, 68, 0.45);
}

.essays-ending p {
  margin: 0;

  color: var(--muted);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 19px;
  font-style: italic;
}


/* Keyboard accessibility */

.essay-spine:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 6px;
}

/* ----------------------------------------
   ABOUT ME
---------------------------------------- */

.about-me-heading {
  max-width: 620px;
}

.about-me-heading h2 em {
  color: var(--accent);
  font-weight: 500;
}

.about-me-content {
  display: grid;
  grid-template-columns: minmax(280px, 460px) 1fr;
  align-items: start;
  gap: 64px;

  max-width: 1180px;
}

.about-photo {
  display: block;
  width: 100%;
  max-width: 460px;
  height: auto;
}

.about-me-bio {
  max-width: 480px;
  padding-top: 4px;
}

.about-me-bio p {
  margin: 0 0 20px;

  color: var(--muted);

  font-size: 16px;
  line-height: 1.8;
}

/* Higher specificity than ".about-me-bio p" above (two classes beat
   one class + one type selector) so this genuinely overrides it,
   rather than losing the cascade despite coming later in the file. */
.about-me-bio .about-me-greeting {
  margin: 0 0 20px;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(22px, 2.2vw, 26px);
  font-weight: 500;
  color: var(--ink);
}

.about-me-bio p:last-of-type {
  margin-bottom: 0;
}

.about-me-bio .text-link {
  display: inline-block;
  margin-top: 8px;
}

.about-me-currently {
  margin-top: 56px;
  padding-top: 32px;
  max-width: 1180px;

  border-top: 1px solid var(--line);
}

.about-me-currently ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 22px;

  margin: 14px 0 0;
  padding: 0;

  list-style: none;
}

.about-me-currently li {
  position: relative;
  padding-left: 14px;

  color: var(--muted);

  font-size: 14px;
  line-height: 1.6;
}

.about-me-currently li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.65em;

  width: 4px;
  height: 4px;
  border-radius: 50%;

  background: var(--accent);
}

@media (max-width: 760px) {
  .about-me-content {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .about-photo {
    max-width: 320px;
  }

  .about-me-bio {
    max-width: none;
  }

  .about-me-currently ul {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
}


.contact {
  text-align: center;
  max-width: 760px;
  margin: auto;
}
.contact h2 { margin-bottom: 20px; }
footer {
  padding: 35px 7vw;
  color: var(--muted);
  border-top: 1px solid var(--line);
}

/* Gallery entrance panels live further down in this file — see
   "GALLERY — MUSEUM ENTRANCE" near the end of the stylesheet. */

@media (max-width: 760px) {

  .nav {
    align-items: flex-start;
  }

  .nav nav {
    display: none;
  }

  .split-section,
  .map-card,
  .three,
  .two {
    grid-template-columns: 1fr;
  }

  .map-card {
    min-height: auto;
  }

  /* The globe stays a real, draggable sphere on mobile (touch drag
     works via the same pointer-event handlers as desktop) — it just
     gets a shorter stage and a slightly larger marker hit area, since
     fingers are less precise than a cursor. */
  .globe-stage {
    min-height: 320px;
  }

  .globe-marker {
    width: 32px;
    height: 32px;
  }

  .map-note {
    padding: 40px 28px;
  }

  /* Same reasoning as .globe-marker just above: fingers are less
     precise than a cursor, so the tappable box grows even though the
     arrow glyph itself stays visually about the same size. */
  .map-note-arrow {
    width: 34px;
    height: 34px;

    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }

  .map-note-heading {
    gap: 6px;
  }

  h1 {
    font-size: 72px;
  }


  /* Hero mobile — stack into one column; the tall hero photo gets its
     own aspect-ratio box (rather than the desktop's fixed 700px height)
     so it always shows a full, uncropped-feeling slice of the image at
     any phone width. Fixes the previous bug where a narrow single-column
     width made `background-size: 100%` render the image shorter than
     its container, causing the browser to tile (repeat) it vertically —
     the "重影" ghosting. `cover` + `no-repeat` + a tuned vertical
     position keep it to one clean, elegant crop instead. */

  .hero {
    grid-template-columns: 1fr;
    min-height: auto;
    gap: 36px;
    padding: 20px 0 56px;
  }

  .hero-left {
    padding-top: 12px;
    padding-left: 0;
  }

  .hero-copy {
    max-width: 300px;
  }

  .hero-right {
    min-height: auto;
    margin-right: 0;
    aspect-ratio: 2 / 3;
  }

  .hero-photo {
    border-radius: 0 0 0 56px;

    background-size: cover;
    background-repeat: no-repeat;
    background-position: center 64%;
  }


  /* Explore mobile */

  .explore-section {
    padding: 90px 0;
  }

  .explore-intro {
    margin-bottom: 55px;
  }

  .explore-intro h2 {
    font-size: 54px;
  }

  .explore-copy {
    max-width: 34rem;
    margin-top: 28px;
  }

  .explore-item {
    grid-template-columns: 36px 1fr 30px;
    gap: 12px;

    min-height: 116px;
    padding: 18px 4px;
  }

  .explore-title h3 {
    font-size: 36px;
  }

  .explore-title p {
    max-width: 230px;

    font-size: 12px;
    line-height: 1.5;
  }

  .explore-preview {
    display: none;
  }

  .explore-item:hover {
    padding-left: 4px;
    padding-right: 4px;
  }

  .explore-item:hover .explore-title {
    transform: none;
  }


  /* Gallery mobile rules live in "GALLERY — MUSEUM ENTRANCE" near
     the end of this file. */

    /* Essays mobile */

  .essays-section {
    padding-top: 95px;
    padding-bottom: 95px;
  }

  .essays-intro {
    grid-template-columns: 1fr;
    gap: 28px;

    margin-bottom: 58px;
  }

  .essays-heading h2 {
    font-size: 53px;
  }

  .essays-intro-copy {
    max-width: 310px;
  }

 .essay-spine {
    grid-template-columns: 22px minmax(0, 1fr) 23px;
    gap: 12px;

    min-height: 145px;
    padding: 22px 4px 22px 12px;

    transform: none;
  }

  .essay-spine::after {
    top: 16px;
    bottom: 16px;
  }

  .essay-title h3 {
    font-size: 28px;
    line-height: 1.02;
  }

  .essay-type {
    margin-top: 9px;

    font-size: 9px;
  }

  .essay-quote {
    grid-column: 2 / 3;

    max-width: 285px;
    margin-top: -4px;

    font-size: 16px;

    opacity: 0.72;
    transform: none;
  }

  .essay-arrow {
    grid-column: 3;
    grid-row: 1 / 3;

    align-self: center;

    width: 17px;
    height: 17px;
    opacity: 0.65;
  }

  .essay-spine:hover {
    transform: none;

    padding-left: 12px;
    padding-right: 4px;

    box-shadow: none;
  }

  .essay-spine:hover .essay-title {
    transform: none;
  }

 .essay-spine:hover .essay-dot {
  transform: scale(1);
  box-shadow: none;
  }

  .essay-spine:hover .essay-arrow {
    transform: none;
  }

  .essays-ending {
    justify-content: flex-start;
  }
}


/* ========================================
   LONGFORM ESSAY — EDITORIAL LAYOUT
======================================== */


/* ----------------------------------------
   READING PROGRESS
---------------------------------------- */

.essay-page .reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;

  z-index: 30;

  height: 2px;

  pointer-events: none;
}

.essay-page .reading-progress-bar {
  display: block;

  width: 100%;
  height: 100%;

  background: var(--accent);

  transform: scaleX(0);
  transform-origin: left center;

  will-change: transform;
}


/* ----------------------------------------
   PAGE STRUCTURE
---------------------------------------- */

.essay-page,
.field-note-page {
  background: var(--bg);
}

.article-main {
  padding: 0 7vw;
}

.longform-essay {
  width: 100%;
  max-width: 1120px;

  margin: 0 auto;
}


/* ----------------------------------------
   ARTICLE NAVIGATION
---------------------------------------- */

.essay-page-nav .logo {
  color: var(--ink);
  text-decoration: none;
}

.article-back {
  display: inline-block;

  margin-bottom: 76px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;

  transition:
    color 0.3s ease,
    transform 0.3s ease;
}

.article-back:hover {
  color: var(--accent);
  transform: translateX(-3px);
}


/* ----------------------------------------
   ARTICLE HEADER
---------------------------------------- */

.article-header {
  display: block;

  width: 100%;
  max-width: 920px;

  padding: 105px 0 118px;
}

.article-header .section-label {
  margin: 0 0 25px;
}


/* Main title */

.article-header h1 {
  max-width: 920px;
  margin: 0;

  color: #26211e;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(56px, 6.3vw, 91px);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 0.98;
}

.article-header h1 em {
  display: block;

  margin-top: 6px;

  color: var(--accent);

  font-style: italic;
  font-weight: 500;
}


/* Subtitle */

.article-subtitle {
  max-width: 570px;

  margin: 43px 0 0;

  color: var(--muted);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(21px, 1.8vw, 27px);
  font-weight: 500;
  letter-spacing: -0.005em;
  line-height: 1.48;
}


/* Author, date and reading time */

.article-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 11px;

  margin-top: 36px;

  color: rgba(31, 27, 24, 0.56);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1;
  text-transform: uppercase;
}

.article-meta-dot {
  display: block;
  flex: 0 0 auto;

  width: 3px;
  height: 3px;

  border-radius: 50%;

  background: var(--accent);

  opacity: 0.55;
}


/* ----------------------------------------
   ARTICLE BODY
---------------------------------------- */

.article-body {
  position: relative;

  width: min(100%, 680px);

  margin: 0 auto;
  padding: 116px 0 155px;

  border-top: 1px solid var(--line);
}

.article-body::before {
  content: "";

  position: absolute;
  top: -1px;
  left: 0;

  width: 72px;
  height: 1px;

  background: var(--accent);

  opacity: 0.62;
}


/* Normal paragraphs */

.article-body p {
  margin: 0 0 1.85em;

  color: rgba(31, 27, 24, 0.8);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 16px;
  font-weight: 300;
  letter-spacing: 0.005em;
  line-height: 1.92;
}

.article-body p:last-child {
  margin-bottom: 0;
}


/* ----------------------------------------
   LEAD PARAGRAPH
---------------------------------------- */

.article-body .article-lead {
  margin-bottom: 1.55em;

  color: #302925;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(25px, 2.4vw, 32px);
  font-weight: 500;
  letter-spacing: -0.012em;
  line-height: 1.5;
}


/* Drop cap */

.drop-cap {
  float: left;

  margin: 0.075em 0.13em 0 0;

  color: var(--accent);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 3.5em;
  font-style: normal;
  font-weight: 500;
  line-height: 0.75;
}


/* Inline CJK text set within a Latin-script paragraph (e.g. a quoted
   Chinese line, title or name inside an essay/field note) reads
   larger next to Latin type at the same font-size, since CJK glyphs
   fill a full em-square while Latin letters sit on a smaller
   x-height. Sizing down to ~89% brings the two scripts into visual
   balance, so a quoted line reads as part of the prose rather than a
   heavier, dropped-in annotation. Only applied where CJK sits inline
   against Latin text in the same line/sentence — a standalone
   all-Chinese line (e.g. a field note's own hover-card quote) has
   nothing to balance against, so is left at full size and this class
   isn't used there.

   Weight is deliberately left unset here (inherits the surrounding
   paragraph's own weight) because the right correction is context-
   dependent: Noto Serif SC's regular weight reads heavier than
   Cormorant Garamond at the same size when a paragraph's base weight
   is already high (e.g. .article-lead's 500), but that same 400
   would look *heavier*, not lighter, inside a 300-weight body
   paragraph. Combine with .cjk-serif below when the surrounding text
   is a 500-weight serif lead paragraph; leave unpaired (size only)
   inside regular 300-weight body copy. */
.cjk-inline {
  font-size: 0.89em;
}

/* Pair with .cjk-inline inside a 500-weight serif context (e.g.
   .article-lead, set in "Cormorant Garamond"/"Noto Serif SC") to
   also step the CJK down one loaded weight (500 → 400) so it reads
   lighter, not just smaller, next to the surrounding Latin text. */
.cjk-serif {
  font-weight: 400;
}


/* Hidden replacement letter for screen readers */

.visually-hidden {
  position: absolute;

  width: 1px;
  height: 1px;

  padding: 0;
  margin: -1px;

  overflow: hidden;

  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);

  white-space: nowrap;

  border: 0;
}


/* Opening pause */

.article-bridge {
  margin-top: 49px !important;
  margin-bottom: 27px !important;

  color: #6e4b3b !important;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif !important;
  font-size: 23px !important;
  font-style: italic;
  font-weight: 500 !important;
  letter-spacing: -0.01em !important;
  line-height: 1.5 !important;
}


/* ----------------------------------------
   FIELD NOTE DIALOGUE
   For a field note that quotes a real
   back-and-forth (e.g. "What Currencies Are
   You Optimising For?"). Each speaker's turn
   sits in its own indented, left-bordered
   block with a small uppercase initial, so the
   quoted exchange reads as a distinct, quoted
   voice rather than blending into the
   surrounding first-person narration before and
   after it — the same "set apart, not just
   styled" logic as .article-pullquote, but
   quieter (body-sized text, no italics) since
   this is dialogue, not a single quotable line.
---------------------------------------- */

.field-note-dialogue {
  margin: 50px 0;
}

.dialogue-turn {
  padding-left: 22px;

  border-left: 2px solid rgba(155, 95, 68, 0.3);
}

.dialogue-turn + .dialogue-turn {
  margin-top: 34px;
}

.dialogue-speaker {
  display: block;
  margin-bottom: 12px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.dialogue-turn p {
  margin: 0 0 1.3em;

  color: rgba(31, 27, 24, 0.8);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.8;
}

.dialogue-turn p:last-child {
  margin-bottom: 0;
}


/* ----------------------------------------
   ARTICLE SECTIONS
---------------------------------------- */

.article-section {
  margin: 0;
  padding: 0;
}

.article-section + .article-section {
  margin-top: 0;
}


/* Section headings */

.article-body h2 {
  max-width: 650px;

  margin: 112px 0 43px;

  color: #302925;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(35px, 3.8vw, 48px);
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 1.08;
}

.article-body h2::before {
  content: "";

  display: block;

  width: 32px;
  height: 1px;

  margin-bottom: 26px;

  background: rgba(155, 95, 68, 0.5);
}


/* ----------------------------------------
   PULL QUOTES
---------------------------------------- */

.article-pullquote {
  position: relative;

  width: calc(100% + 72px);

  margin: 77px 0 79px -36px;
  padding: 8px 0 8px 43px;

  color: #8d5942;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(27px, 2.75vw, 35px);
  font-style: italic;
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.42;

  border: none;
}

.article-pullquote::before {
  content: "";

  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;

  display: block;

  width: 1px;

  background: rgba(155, 95, 68, 0.72);
}

.article-pullquote::after {
  content: "";

  position: absolute;
  top: 50%;
  left: -4px;

  width: 9px;
  height: 9px;

  border: 1px solid rgba(155, 95, 68, 0.58);
  border-radius: 50%;

  background: var(--bg);

  transform: translateY(-50%);
}


/* ----------------------------------------
   ARTICLE TABLE
   Used for genuine tabular content inside a
   longform essay (e.g. a definitions glossary)
   — not decorative, so styled plainly: thin
   rules, no shading, no rounded corners,
   matching the essay's classic typographic
   register rather than a dashboard look.
---------------------------------------- */

.article-table-wrap {
  margin: 62px 0;

  overflow-x: auto;
}

.article-table {
  width: 100%;

  border-collapse: collapse;
}

.article-table caption {
  margin-bottom: 18px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 12.5px;
  font-style: italic;
  text-align: left;
}

.article-table th,
.article-table td {
  padding: 14px 20px 14px 0;

  color: rgba(31, 27, 24, 0.8);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 14px;
  font-weight: 300;
  line-height: 1.6;
  text-align: left;
  vertical-align: top;

  border-bottom: 1px solid var(--line);
}

.article-table thead th {
  padding-top: 0;

  color: var(--accent);

  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;

  border-bottom: 1px solid rgba(155, 95, 68, 0.4);
}

.article-table tbody th {
  padding-right: 24px;

  color: #302925;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 16px;
  font-weight: 500;
  white-space: nowrap;
}


/* ----------------------------------------
   ARTICLE FIGURE
   A text-based diagram (three linked columns)
   for essays that reference a conceptual
   framework — same restrained register as the
   table above, no icons or colour-coding.
---------------------------------------- */

.article-figure {
  margin: 62px 0;
}

.article-figure-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr;
  align-items: start;
  gap: 20px;

  padding: 36px 0;

  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.article-figure-col-title {
  margin: 0 0 4px;

  color: #302925;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 18px;
  font-weight: 500;
}

.article-figure-col-sub {
  margin: 0 0 12px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-style: italic;
}

.article-figure-col ul {
  margin: 12px 0 0;
  padding-left: 18px;

  color: rgba(31, 27, 24, 0.75);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 13px;
  font-weight: 300;
  line-height: 1.6;
}

.article-figure-col li {
  margin-bottom: 8px;
}

.article-figure-col li::marker {
  color: rgba(155, 95, 68, 0.6);
}

.article-figure-arrow {
  align-self: center;

  color: rgba(155, 95, 68, 0.55);

  font-family: "Inter", sans-serif;
  font-size: 18px;
}

.article-figure figcaption {
  margin-top: 20px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 12.5px;
  font-style: italic;
  line-height: 1.6;
}


/* ----------------------------------------
   FINAL PARAGRAPH
---------------------------------------- */

.article-ending {
  position: relative;

  margin-top: 94px !important;
  margin-bottom: 0 !important;
  padding: 62px 0 0 43px;

  color: #4b3930 !important;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif !important;
  font-size: clamp(25px, 2.65vw, 34px) !important;
  font-style: italic;
  font-weight: 500 !important;
  letter-spacing: -0.012em !important;
  line-height: 1.5 !important;

  border-top: 1px solid rgba(31, 27, 24, 0.12);
}

.article-ending::before {
  content: "—";

  position: absolute;
  top: 57px;
  left: 0;

  color: var(--accent);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: 24px;
  font-style: normal;
  font-weight: 500;
}


/* ----------------------------------------
   FURTHER READING
---------------------------------------- */

.article-references {
  margin-top: 148px;
  padding-top: 46px;

  border-top: 1px solid var(--line);
}

.article-references .section-label {
  margin: 0 0 32px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
}

.article-references ol {
  margin: 0;
  padding-left: 19px;
}

.article-references li {
  margin-bottom: 17px;
  padding-left: 10px;

  color: rgba(31, 27, 24, 0.58);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 300;
  letter-spacing: 0.002em;
  line-height: 1.75;
}

.article-references li::marker {
  color: rgba(155, 95, 68, 0.72);

  font-size: 10px;
}

.article-references em {
  font-style: italic;
}


/* ----------------------------------------
   ARTICLE FOOTER
---------------------------------------- */

.article-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 30px;

  padding: 39px 7vw;

  color: var(--muted);

  border-top: 1px solid var(--line);
}

.article-footer a {
  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-decoration: none;
  text-transform: uppercase;

  transition:
    color 0.3s ease,
    transform 0.3s ease;
}

.article-footer a:hover {
  color: var(--accent);
  transform: translateX(-3px);
}

.article-footer p {
  margin: 0;

  font-size: 11px;
}


/* ----------------------------------------
   SELECTION
---------------------------------------- */

.essay-page ::selection,
.field-note-page ::selection {
  color: var(--ink);
  background: rgba(155, 95, 68, 0.18);
}


/* ----------------------------------------
   TABLET
---------------------------------------- */

@media (max-width: 960px) {

  .article-header {
    max-width: 820px;
  }

  .article-pullquote {
    width: calc(100% + 36px);

    margin-left: -18px;
    padding-left: 36px;
  }

}


/* ----------------------------------------
   MOBILE
---------------------------------------- */

@media (max-width: 760px) {

  .article-main {
    padding: 0 6vw;
  }


  /* Header */

  .article-header {
    padding: 70px 0 83px;
  }

  .article-back {
    margin-bottom: 58px;
  }

  .article-header .section-label {
    margin-bottom: 20px;
  }

  .article-header h1 {
    font-size: clamp(47px, 13.4vw, 63px);
    letter-spacing: -0.043em;
    line-height: 0.98;
  }

  .article-header h1 em {
    margin-top: 5px;
  }

  .article-subtitle {
    max-width: 330px;

    margin-top: 30px;

    font-size: 21px;
    line-height: 1.5;
  }

  .article-meta {
    gap: 8px;

    margin-top: 28px;

    font-size: 9px;
    letter-spacing: 0.1em;
    line-height: 1.5;
  }


  /* Body */

  .article-body {
    width: 100%;

    padding: 76px 0 106px;
  }

  .article-body::before {
    width: 52px;
  }

  .article-body p {
    margin-bottom: 1.58em;

    font-size: 15.5px;
    letter-spacing: 0;
    line-height: 1.84;
  }

  .article-body .article-lead {
    margin-bottom: 1.48em;

    font-size: 26px;
    line-height: 1.48;
  }


  /* Drop cap */

  .drop-cap {
    margin-top: 0.08em;
    margin-right: 0.11em;

    font-size: 3.22em;
  }


  /* Opening pause */

  .article-bridge {
    margin-top: 40px !important;
    margin-bottom: 24px !important;

    font-size: 21px !important;
  }


  /* Headings */

  .article-body h2 {
    margin: 79px 0 30px;

    font-size: 38px;
    line-height: 1.08;
  }

  .article-body h2::before {
    width: 28px;

    margin-bottom: 22px;
  }


  /* Pull quotes */

  .article-pullquote {
    width: 100%;

    margin: 59px 0 63px;
    padding: 4px 0 4px 28px;

    font-size: 27px;
    line-height: 1.42;
  }

  .article-pullquote::before {
    top: 2px;
    bottom: 2px;
  }

  .article-pullquote::after {
    left: -4px;
  }


  /* Ending */

  .article-ending {
    margin-top: 76px !important;
    padding: 49px 0 0 31px;

    font-size: 27px !important;
    line-height: 1.48 !important;
  }

  .article-ending::before {
    top: 44px;

    font-size: 22px;
  }


  /* Table */

  .article-table th,
  .article-table td {
    padding: 12px 14px 12px 0;

    font-size: 13px;
  }

  .article-table tbody th {
    font-size: 15px;
  }


  /* Figure — stacks to a single column, arrows rotate to point down */

  .article-figure-grid {
    grid-template-columns: 1fr;

    padding: 28px 0;
  }

  .article-figure-arrow {
    justify-self: center;

    transform: rotate(90deg);
  }


  /* Field note dialogue */

  .dialogue-turn {
    padding-left: 16px;
  }

  .dialogue-turn p {
    font-size: 15.5px;
    line-height: 1.72;
  }


  /* References */

  .article-references {
    margin-top: 114px;
    padding-top: 38px;
  }

  .article-references .section-label {
    margin-bottom: 27px;
  }

  .article-references li {
    margin-bottom: 16px;

    font-size: 10.5px;
    line-height: 1.72;
  }


  /* Footer */

  .article-footer {
    align-items: flex-start;
    flex-direction: column;

    padding: 32px 6vw;
  }

}


/* ----------------------------------------
   REDUCED MOTION
---------------------------------------- */

@media (prefers-reduced-motion: reduce) {

  .article-back,
  .article-footer a {
    transition: none;
  }

}


/* ========================================
   FIELD NOTE — INTIMATE READING PAGE
   Shares the longform article system above
   (typography, width, grain, nav, body
   treatment) but with a shorter, quieter
   header — closer to a private notebook
   than a formal publication.
======================================== */

.field-note-page-nav .logo {
  color: var(--ink);
  text-decoration: none;
}

.field-note-page .article-back {
  margin-bottom: 44px;
}

.field-note-page .article-header {
  padding: 54px 0 58px;
}

.field-note-page .article-header h1 {
  max-width: 700px;

  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.14;
}

.field-note-page .article-meta {
  margin-top: 20px;
}


/* Dialogue speaker label — used on notes written as conversation */

.field-note-page .dialogue-speaker {
  display: inline-block;

  margin-right: 10px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

@media (max-width: 760px) {

  .field-note-page .article-back {
    margin-bottom: 34px;
  }

  .field-note-page .article-header {
    padding: 46px 0 50px;
  }

  .field-note-page .article-header h1 {
    font-size: clamp(28px, 8.6vw, 38px);
    letter-spacing: -0.008em;
    line-height: 1.18;
  }

  .field-note-page .article-meta {
    margin-top: 16px;
  }

}


/* ========================================
   GALLERY — MUSEUM ENTRANCE
   Two independent modules (Photographs,
   Drawings) reached through a single pair
   of full-bleed entrance panels. Not a
   portfolio grid — every image gets room
   to breathe. See CLAUDE.md → "Gallery
   architecture" for the file structure.
======================================== */


/* ----------------------------------------
   LANDING ENTRANCE (index.html #gallery)
---------------------------------------- */

.gallery-entrance {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 32px;

  margin-top: 64px;
}

.gallery-panel {
  position: relative;

  display: block;

  height: 640px;

  overflow: hidden;

  color: #fffaf3;
  text-decoration: none;

  cursor: pointer;
}

/* Scroll reveal stagger — three panels side by side; see "SCROLL
   REVEAL" further up for the shared .reveal-up recipe. */
.gallery-panel:nth-child(2) { --reveal-delay: 0.12s; }
.gallery-panel:nth-child(3) { --reveal-delay: 0.24s; }

.gallery-panel-image {
  position: absolute;
  inset: 0;

  background-size: cover;
  background-position: center;

  filter: saturate(0.85);

  transform: scale(1);

  transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
}

.gallery-panel-image--placeholder {
  background-image:
    linear-gradient(
      150deg,
      rgba(234, 220, 204, 0.9),
      rgba(248, 243, 236, 0.9)
    );
}

.gallery-panel:hover .gallery-panel-image {
  transform: scale(1.03);
}

.gallery-panel::after {
  content: "";

  position: absolute;
  inset: 0;
  z-index: 1;

  pointer-events: none;

  background: linear-gradient(
    180deg,
    transparent 38%,
    rgba(31, 27, 24, 0.6) 100%
  );
}

.gallery-panel-content {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;

  padding: 40px 40px 36px;
}

.gallery-panel-title {
  display: block;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(34px, 3vw, 46px);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;

  color: rgba(255, 250, 243, 0.88);

  transition: color 0.7s ease;
}

.gallery-panel:hover .gallery-panel-title {
  color: #fffaf3;
}

.gallery-panel-copy {
  display: block;

  margin-top: 12px;
  max-width: 260px;

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 14px;
  line-height: 1.65;

  color: rgba(255, 250, 243, 0.72);
}

.gallery-panel-count {
  display: block;

  margin-top: 20px;

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;

  color: rgba(255, 250, 243, 0.5);
}

.gallery-panel:focus-visible {
  outline: 1px solid rgba(255, 250, 243, 0.7);
  outline-offset: -8px;
}


/* ----------------------------------------
   EXHIBITION PAGE CHROME
   (gallery/photographs.html, gallery/drawings.html)
---------------------------------------- */

.gallery-page {
  background: #f8f7f4;
}

.gallery-page ::selection {
  color: var(--ink);
  background: rgba(155, 95, 68, 0.18);
}

.gallery-page-nav .logo {
  color: var(--ink);
  text-decoration: none;
}

.gallery-exhibition {
  padding: 0 7vw;
}

.exhibit-header {
  max-width: 900px;
  margin: 0 auto;
  padding: 100px 0 90px;
}

.exhibit-back {
  display: inline-block;

  margin-bottom: 64px;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;

  transition: color 0.3s ease, transform 0.3s ease;
}

.exhibit-back:hover {
  color: var(--accent);
  transform: translateX(-3px);
}

.exhibit-breadcrumb {
  margin: 0 0 22px;

  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.exhibit-header h1 {
  margin: 0;

  color: #26211e;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-size: clamp(56px, 7vw, 100px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 0.96;
}

.exhibit-subtitle {
  max-width: 520px;
  margin: 26px 0 0;

  color: var(--muted);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-style: italic;
  font-size: clamp(20px, 1.8vw, 26px);
  line-height: 1.55;
}


/* ----------------------------------------
   COLLECTIONS
---------------------------------------- */

.exhibit-collections {
  max-width: 1500px;
  margin: 0 auto;
}

.exhibit-collection {
  padding: 120px 0;

  border-top: 1px solid var(--line);
}

.exhibit-collection:first-child {
  padding-top: 0;
  border-top: none;
}

.exhibit-collection-intro {
  max-width: 620px;
  margin: 0 auto 72px;

  text-align: center;
}

.exhibit-collection-title {
  margin: 0;

  color: #26211e;

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-weight: 500;
  font-size: clamp(32px, 3.4vw, 50px);
  letter-spacing: -0.02em;
  line-height: 1.05;
}

.exhibit-collection--featured .exhibit-collection-title {
  font-size: clamp(42px, 4.4vw, 64px);
}

.exhibit-collection-sentence {
  margin: 18px 0 0;

  color: var(--muted);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 15px;
  line-height: 1.75;
}

.exhibit-coming-soon {
  margin: 0;
  padding-bottom: 20px;

  color: var(--muted);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-style: italic;
  font-size: 19px;
  text-align: center;
}

.exhibit-collection-count {
  margin: 14px 0 0;

  color: rgba(155, 95, 68, 0.6);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}


/* ----------------------------------------
   MASONRY (Photographs)
---------------------------------------- */

.exhibit-grid--masonry {
  column-count: 3;
  column-gap: 28px;
}

.exhibit-collection--featured .exhibit-grid--masonry {
  column-count: 2;
  column-gap: 40px;
}

.exhibit-grid--masonry .exhibit-tile {
  margin-bottom: 28px;
}


/* ----------------------------------------
   EDITORIAL GRID (Drawings)

   Unlike the Photographs masonry, drawings keep their natural
   proportions — no forced cropping. A calmer, more structured grid:
   fixed columns with row alignment, each tile's own aspect-ratio set
   inline from its data (see gallery.js createTile), generous gaps so
   every piece reads as an individual work rather than a photo stream.
---------------------------------------- */

.exhibit-grid--editorial {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-items: start;
  gap: 56px 40px;
}

.exhibit-tile--span2 {
  grid-column: span 2;
}


/* ----------------------------------------
   TILES
---------------------------------------- */

.exhibit-tile {
  position: relative;

  display: block;
  width: 100%;

  padding: 0;

  background: none;
  border: none;

  overflow: hidden;
  cursor: pointer;

  opacity: 0;
  transform: translateY(18px);

  transition: opacity 0.9s ease, transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.exhibit-tile.is-revealed {
  opacity: 1;
  transform: none;
}

.exhibit-tile--portrait { aspect-ratio: 3 / 4; }
.exhibit-tile--square   { aspect-ratio: 1 / 1; }
.exhibit-tile--landscape{ aspect-ratio: 4 / 3; }
.exhibit-tile--tall     { aspect-ratio: 2 / 3; }
.exhibit-tile--wide     { aspect-ratio: 16 / 9; }

.exhibit-tile img {
  display: block;

  width: 100%;
  height: 100%;

  object-fit: cover;

  filter: saturate(0.85);

  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1), filter 0.6s ease;
}

/* Real photographs (see .exhibit-tile--natural in gallery.js) sit in
   a tile already sized to their own measured aspect ratio, so
   object-fit: contain here fills the box exactly with zero
   letterboxing — this is a safety net against ever cropping real
   content, not a visual change from `cover`, since the two produce
   an identical result once the box ratio equals the image ratio. */
.exhibit-tile--natural img {
  object-fit: contain;
}

.exhibit-tile:hover img,
.exhibit-tile:focus-visible img {
  transform: scale(1.03);
  filter: saturate(0.95);
}

.exhibit-tile-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;

  width: 100%;
  height: 100%;

  background: linear-gradient(160deg, #eee3d3, #f6efe4);

  transition: background 0.6s ease;
}

.exhibit-tile:hover .exhibit-tile-placeholder,
.exhibit-tile:focus-visible .exhibit-tile-placeholder {
  background: linear-gradient(160deg, #e8dac6, #f3ece0);
}


/* Editorial tiles (Drawings) — contained, not cropped: each work
   sits on its own quiet mat instead of bleeding to the tile edge. */

.exhibit-tile--editorial {
  overflow: visible;

  background: #fcfbf9;
  padding: 14px;

  border: 1px solid var(--line);
}

.exhibit-tile--editorial img {
  object-fit: contain;

  filter: none;
}

.exhibit-tile--editorial:hover img,
.exhibit-tile--editorial:focus-visible img {
  transform: scale(1.015);
  filter: none;
}

.exhibit-tile--editorial .exhibit-tile-placeholder {
  background: linear-gradient(160deg, #f1ede4, #f8f6f1);
}

.exhibit-tile--editorial:hover .exhibit-tile-placeholder,
.exhibit-tile--editorial:focus-visible .exhibit-tile-placeholder {
  background: linear-gradient(160deg, #ece5d6, #f5f2ea);
}

.exhibit-tile--comics {
  grid-column: span 2;
}

.exhibit-tile-index {
  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;

  color: rgba(155, 95, 68, 0.55);
}

.exhibit-tile:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}


/* ----------------------------------------
   LIGHTBOX
---------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;

  display: flex;
  align-items: center;
  justify-content: center;

  background: rgba(20, 17, 15, 0.94);

  opacity: 0;
  visibility: hidden;

  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}

.lightbox.is-open {
  visibility: visible;
}

.lightbox.is-visible {
  opacity: 1;
  transition: opacity 0.5s ease, visibility 0s linear 0s;
}

.lightbox-stage {
  position: relative;

  display: flex;
  align-items: center;
  justify-content: center;

  max-width: 88vw;
  max-height: 82vh;
}

.lightbox-image {
  display: block;

  max-width: 88vw;
  max-height: 82vh;

  object-fit: contain;

  opacity: 0;
  transform: scale(0.98);

  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.lightbox.is-visible .lightbox-image {
  opacity: 1;
  transform: scale(1);
}

.lightbox-placeholder {
  display: none;
  align-items: center;
  justify-content: center;

  width: 60vw;
  max-width: 640px;
  aspect-ratio: 4 / 5;

  background: linear-gradient(160deg, #2a2420, #171310);
}

.lightbox-placeholder-index {
  color: rgba(248, 243, 236, 0.35);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.2em;
}

.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;

  background: none;
  border: none;

  color: rgba(248, 243, 236, 0.72);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-weight: 300;

  cursor: pointer;

  transition: color 0.35s ease, opacity 0.35s ease;
}

.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  color: #fffaf3;
}

.lightbox-close {
  top: 24px;
  right: 28px;

  font-size: 28px;
  line-height: 1;
}

.lightbox-prev,
.lightbox-next {
  top: 50%;

  padding: 18px;

  font-size: 22px;

  transform: translateY(-50%);
}

.lightbox-prev { left: 12px; }
.lightbox-next { right: 12px; }

.lightbox-meta {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 48px;

  margin: 0;

  color: rgba(248, 243, 236, 0.72);

  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-style: italic;
  font-size: 16px;
  text-align: center;
}

.lightbox-meta:empty {
  display: none;
}

.lightbox-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 26px;

  margin: 0;

  color: rgba(248, 243, 236, 0.5);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-align: center;
}

body.lightbox-open {
  overflow: hidden;
}


/* ----------------------------------------
   ROOM SWITCHER (Photographs page only)

   One collection ("room") visible at a time.
   Vertical scroll browses photographs inside
   the active room; horizontal click / arrow
   keys / swipe / trackpad gesture changes
   rooms. drawings.html does not use this —
   it keeps the plain vertical stack above.
---------------------------------------- */

.exhibit-header--rooms {
  padding-bottom: 44px;
}

.room-nav {
  position: sticky;
  top: 86px;
  z-index: 4;

  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 36px;

  margin: 0 auto 64px;
  padding: 26px 0;

  background: rgba(248, 247, 244, 0.86);
  backdrop-filter: blur(10px);

  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);

  animation: room-nav-settle 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes room-nav-settle {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.room-nav-prev,
.room-nav-next {
  display: inline-flex;
  align-items: baseline;
  gap: 9px;

  padding: 0;

  background: none;
  border: none;

  color: rgba(31, 27, 24, 0.38);
  cursor: pointer;

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.03em;
  white-space: nowrap;

  transition: color 0.4s ease;
}

.room-nav-prev:hover,
.room-nav-next:hover {
  color: rgba(31, 27, 24, 0.7);
}

.room-nav-arrow {
  display: inline-block;

  color: var(--accent);
  opacity: 0.55;

  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.4s ease;
}

.room-nav-prev:hover .room-nav-arrow {
  opacity: 1;
  transform: translateX(-4px);
}

.room-nav-next:hover .room-nav-arrow {
  opacity: 1;
  transform: translateX(4px);
}

.room-nav-current {
  color: var(--accent);

  font-family: "Inter", "Noto Sans SC", sans-serif;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.room-nav-prev:focus-visible,
.room-nav-next:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 6px;
}

.room-stage {
  position: relative;

  max-width: 1500px;
  margin: 0 auto;

  overflow-x: hidden;

  touch-action: pan-y;
}

.room-stage-edge {
  position: fixed;
  top: 96px;
  bottom: 0;

  width: 56px;
  z-index: 3;

  pointer-events: none;
}

.room-stage-edge--left {
  left: 0;
  background: linear-gradient(
    90deg,
    #f8f7f4 0%,
    rgba(248, 247, 244, 0) 100%
  );
}

.room-stage-edge--right {
  right: 0;
  background: linear-gradient(
    270deg,
    #f8f7f4 0%,
    rgba(248, 247, 244, 0) 100%
  );
}

.room-panel {
  display: none;

  transform: none;
  opacity: 1;
}

.room-panel.is-active {
  display: block;
}

.room-panel .exhibit-collection {
  padding: 8px 0 60px;
  border-top: none;
}

.room-panel.is-transitioning {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;

  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.5s ease;
}

.room-panel.is-entering-from-right { transform: translateX(36px); opacity: 0; }
.room-panel.is-entering-from-left  { transform: translateX(-36px); opacity: 0; }
.room-panel.is-leaving-to-left     { transform: translateX(-36px); opacity: 0; }
.room-panel.is-leaving-to-right    { transform: translateX(36px); opacity: 0; }


/* ----------------------------------------
   REDUCED MOTION
---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .gallery-panel-image,
  .gallery-panel-title,
  .exhibit-tile,
  .exhibit-tile img,
  .exhibit-tile-placeholder,
  .lightbox,
  .lightbox-image,
  .room-nav-arrow,
  .room-panel.is-transitioning {
    transition-duration: 0.01ms;
  }

  .room-nav {
    animation: none;
  }
}


/* ----------------------------------------
   TABLET
---------------------------------------- */

@media (max-width: 960px) {

  .gallery-entrance {
    grid-template-columns: 1fr 1fr;
  }

  .gallery-entrance .gallery-panel:nth-child(3) {
    grid-column: 1 / -1;
  }

  .exhibit-grid--masonry {
    column-count: 2;
    column-gap: 22px;
  }

  .exhibit-collection--featured .exhibit-grid--masonry {
    column-count: 1;
    max-width: 560px;
    margin: 0 auto;
  }

  .exhibit-grid--editorial {
    grid-template-columns: repeat(2, 1fr);
    gap: 44px 28px;
  }

}


/* ----------------------------------------
   MOBILE
---------------------------------------- */

@media (max-width: 760px) {

  .gallery-entrance {
    grid-template-columns: 1fr;
    gap: 20px;

    margin-top: 44px;
  }

  .gallery-panel {
    height: 460px;
  }

  .gallery-panel-content {
    padding: 30px 26px 28px;
  }

  .gallery-exhibition {
    padding: 0 6vw;
  }

  .exhibit-header {
    padding: 70px 0 64px;
  }

  .exhibit-back {
    margin-bottom: 46px;
  }

  .exhibit-header h1 {
    font-size: clamp(44px, 13vw, 64px);
  }

  .exhibit-subtitle {
    font-size: 20px;
  }

  .exhibit-collection {
    padding: 76px 0;
  }

  .exhibit-collection-intro {
    margin-bottom: 48px;
  }

  .exhibit-grid--masonry {
    column-count: 1;
  }

  .exhibit-collection--featured .exhibit-grid--masonry {
    max-width: none;
  }

  .exhibit-grid--editorial {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .exhibit-tile--span2,
  .exhibit-tile--comics {
    grid-column: span 1;
  }

  .exhibit-collection-count {
    margin-top: 10px;
  }

  .lightbox-prev,
  .lightbox-next {
    padding: 10px;
    font-size: 18px;
  }

  .lightbox-close {
    top: 14px;
    right: 16px;
  }

  .lightbox-caption {
    bottom: 16px;
  }

  .exhibit-header--rooms {
    padding-bottom: 34px;
  }

  .room-nav {
    top: 76px;

    gap: 16px;

    margin-bottom: 44px;
    padding: 18px 0;
  }

  .room-nav-prev,
  .room-nav-next {
    gap: 5px;

    font-size: 11px;
  }

  .room-nav-prev .room-nav-label,
  .room-nav-next .room-nav-label {
    display: none;
  }

  .room-nav-current {
    font-size: 13px;
  }

  .room-stage-edge {
    top: 86px;

    width: 28px;
  }

  .room-panel .exhibit-collection {
    padding: 4px 0 44px;
  }

}


/* ========================================
   CUSTOM CURSOR

   Site-wide (see cursor.js — included on every page). Reuses the
   existing palette (--accent) rather than inventing a new colour;
   the values below are the only things cursor.js expects to find
   here, and are the ones to tune first.
======================================== */

/* EDIT POINT — size, colour, opacity and easing.
   --cursor-rest-scale is --cursor-size ÷ --cursor-hover-size, kept
   as a plain number because CSS calc() cannot divide two lengths —
   update it together with either size if you change them. */
:root {
  --cursor-size: 11px;
  --cursor-hover-size: 32px;
  --cursor-rest-scale: 0.25;

  --cursor-color-rgb: 155, 95, 68; /* matches --accent (#9b5f44) */
  --cursor-rest-opacity: 0.6;
  --cursor-hover-opacity: 0.38;
  --cursor-press-scale: 0.7;

  --cursor-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --cursor-ease-duration: 0.5s;
}

/* Applied to <html> by cursor.js only once it has confirmed a fine
   pointer with hover support — never on touch devices, and never if
   the script fails to load, so the native cursor is always the safe
   fallback. !important is deliberate here: it overrides the many
   individual `cursor: pointer` declarations across the site's
   buttons, links and tiles without hunting each one down. */
html.custom-cursor-active,
html.custom-cursor-active * {
  cursor: none !important;
}

/* The site has no text inputs today, but kept for robustness if one
   is ever added — typing still gets a normal caret. */
html.custom-cursor-active input,
html.custom-cursor-active textarea,
html.custom-cursor-active [contenteditable] {
  cursor: text !important;
}

.custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;

  z-index: 9999;
  pointer-events: none;

  opacity: 0;
  transition: opacity 0.3s ease;

  will-change: transform;
}

.custom-cursor.is-visible {
  opacity: 1;
}

.custom-cursor-dot {
  position: absolute;
  top: 0;
  left: 0;

  width: var(--cursor-hover-size);
  height: var(--cursor-hover-size);

  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(var(--cursor-color-rgb), 0.95) 0%,
    rgba(var(--cursor-color-rgb), 0.55) 55%,
    rgba(var(--cursor-color-rgb), 0) 100%
  );
  filter: blur(0.3px);

  opacity: var(--cursor-rest-opacity);
  transform: translate(-50%, -50%) scale(var(--cursor-rest-scale));

  transition: transform var(--cursor-ease-duration) var(--cursor-ease),
    opacity var(--cursor-ease-duration) var(--cursor-ease),
    border-radius var(--cursor-ease-duration) var(--cursor-ease);
}

.custom-cursor-dot.is-hover {
  opacity: var(--cursor-hover-opacity);
  transform: translate(-50%, -50%) scale(1);
}

/* Brief shrink on press — quicker than the hover/rest transition so
   it reads as a small "tap" rather than a slow resize. */
.custom-cursor-dot.is-pressed {
  transition: transform 0.14s ease;
}

.custom-cursor-dot.is-hover.is-pressed {
  transform: translate(-50%, -50%) scale(0.72);
}

.custom-cursor-dot.is-pressed:not(.is-hover) {
  transform: translate(-50%, -50%)
    scale(calc(var(--cursor-rest-scale) * var(--cursor-press-scale)));
}

/* Long-form reading pages (essays, field notes) — a smaller, quieter
   hover state so the cursor never competes with body text. */
.custom-cursor--restrained .custom-cursor-dot.is-hover {
  opacity: calc(var(--cursor-hover-opacity) * 0.7);
  transform: translate(-50%, -50%) scale(0.68);
}

@media (prefers-reduced-motion: reduce) {
  .custom-cursor-dot {
    transition-duration: 0.01ms;
  }
}


/* ========================================
   PIXEL FOX COMPANION (all pages)

   Markup is built entirely by fox.js (included on every page);
   nothing to add anywhere else. Colours are their own small
   palette (--fox-*), distinct from the site's --ink/--accent but
   chosen to sit quietly alongside them — warm, muted, low-contrast.
======================================== */

:root {
  /* Pixel palette — a softer, more muted take on fox-orange than a
     literal swatch match, chosen to sit quietly in this site's warm,
     low-contrast world rather than pop against it. */
  --fox-fur: #dd9a76;
  --fox-fur-light: #f0c9ab;
  --fox-fur-deep: #c9835c;
  --fox-cream: #fbf5ec;
  --fox-shadow: #96796a;
  --fox-ink: #382c26;
  --fox-ground: rgba(56, 44, 38, 0.14);

  /* EDIT POINT — rendered size (viewBox is a fixed 40 x 44). */
  --fox-width: 58px;
  --fox-height: 64px;
}

.pixel-fox {
  position: fixed;
  right: 26px;
  bottom: 20px;

  width: var(--fox-width);
  height: var(--fox-height);

  z-index: 20;
  cursor: pointer;
  pointer-events: auto;

  /* Mobile Safari/Chrome can otherwise wait ~300ms to see whether a
     tap is the start of a double-tap-zoom or scroll gesture before
     firing click — this tells it to treat a tap here as an
     immediate, unambiguous action instead. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;

  /* Fixed positioning, out of document flow — causes no layout
     shift on any existing section, on any page. */
}

.pixel-fox-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Clicks/hover always land on the .pixel-fox container itself, not
   individual shapes — consistent hit-testing regardless of which
   part of the silhouette the pointer happens to be over. */
.pixel-fox-svg,
.pixel-fox-svg * {
  pointer-events: none;
}

.fox-fur { fill: var(--fox-fur); }
.fox-fur-light { fill: var(--fox-fur-light); }
.fox-fur-deep { fill: var(--fox-fur-deep); }
.fox-cream { fill: var(--fox-cream); }
.fox-ink { fill: var(--fox-ink); }
.fox-shadow { fill: var(--fox-shadow); }
.fox-ground { fill: var(--fox-ground); }

.fox-envelope-flap {
  fill: none;
  stroke: var(--fox-shadow);
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
}


/* ---- breathing, tail sway (idle/sitting baseline) ---- */

@keyframes fox-breathe {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.035); }
}

@keyframes fox-breathe-slow {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.018); }
}

.fox-body {
  transform-box: fill-box;
  transform-origin: bottom center;
  animation: fox-breathe 3.2s ease-in-out infinite;
}

.pixel-fox.is-sleeping .fox-body {
  animation: fox-breathe-slow 5.4s ease-in-out infinite;
}

@keyframes fox-tail-sway {
  0%, 100% { transform: rotate(-4deg); }
  50% { transform: rotate(6deg); }
}

.fox-tail {
  transform-box: fill-box;
  transform-origin: 10% 95%;
  animation: fox-tail-sway 4.4s ease-in-out infinite;
}

.pixel-fox.is-sitting .fox-tail {
  animation-duration: 5.2s;
}

/* Lying/sleeping — the tail settles and, once fully asleep, wraps
   in around the body rather than swaying. */
.pixel-fox.is-lying .fox-tail {
  animation: none;
  transform: rotate(28deg);
  transition: transform 0.6s ease;
}

.pixel-fox.is-sleeping .fox-tail {
  animation: none;
  transform: rotate(132deg) scale(0.96);
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.pixel-fox.is-waking .fox-tail {
  animation: none;
  transform: rotate(-16deg) scale(1.06);
  transition: transform 0.5s ease;
}


/* ---- whole-body pose (sit / lie / sleep / wake / hop) ---- */

.fox-rig {
  transform-box: fill-box;
  transform-origin: bottom center;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.pixel-fox.is-sitting .fox-rig {
  transform: translateY(2px) scaleY(0.95);
}

/* Lying/sleeping — deliberately no scaleX/scaleY squash here: size
   stays constant, only position (settling lower) and a gentle tilt
   change, matching a real curled-up posture rather than a flattened
   one. The tail wrap (above), closed eyes, and slow breathing carry
   the rest of the "asleep" read. */
.pixel-fox.is-lying .fox-rig {
  transform: translateY(4px) rotate(-6deg);
}

.pixel-fox.is-sleeping .fox-rig {
  transform: translateY(5px) rotate(-7deg);
  transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* The one place a brief scale change is appropriate: the stretch
   itself is motion, not a resting pose, so elongating low then
   rising back to full size at 100% is exactly the "stretch first,
   then stand" read — it just settles at the same size it started
   the sleep cycle at, never staying squashed. */
@keyframes fox-stretch {
  0% { transform: translateY(5px) rotate(-7deg); }
  35% { transform: translateY(2px) scaleY(0.82) scaleX(1.2) rotate(-2deg); }
  70% { transform: translateY(-1px) scaleY(1.06) scaleX(0.97) rotate(0deg); }
  100% { transform: translateY(0) scaleY(1) scaleX(1) rotate(0deg); }
}

.pixel-fox.is-waking .fox-rig {
  animation: fox-stretch 0.82s cubic-bezier(0.34, 1.2, 0.4, 1);
}

@keyframes fox-hop {
  0%, 100% { transform: translateY(0); }
  35% { transform: translateY(-7px); }
  60% { transform: translateY(0.5px); }
}

.pixel-fox.is-hopping .fox-rig {
  animation: fox-hop 0.42s ease;
}


/* ---- head: hover look-up, autonomous look-around, fluffy tilt ---- */

.fox-head {
  transform-box: fill-box;
  transform-origin: bottom center;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Default hover look — home/about (no accessory): a plain curious
   look-up. Overridden per accessory below (EDIT POINT — each of the
   four accessory contexts gets its own small, bespoke hover
   reaction rather than sharing this one). */
.pixel-fox.is-looking .fox-head {
  transform: translateY(-2px) rotate(-3deg);
}

/* Gallery — camera does the lifting (see .fox-accessory below); the
   head barely moves, as if steadying a shot. */
.pixel-fox[data-accessory="camera"].is-looking .fox-head {
  transform: translateY(-1px) rotate(-2deg);
}

/* Essays/Field Notes — a persistent slight head-bow at rest, not
   just on hover, so the fox reads as genuinely mid-page rather than
   idly holding a closed book. Hovering (below) deepens the same
   bow further. */
.pixel-fox[data-accessory="book"] .fox-head {
  transform: translateY(1px) rotate(3deg);
}

.pixel-fox[data-accessory="book"].is-looking .fox-head {
  transform: translateY(2px) rotate(5deg);
}

/* Map — looks down toward the compass tucked at its paw. */
.pixel-fox[data-accessory="compass"].is-looking .fox-head {
  transform: translateY(1.5px) rotate(7deg);
}

/* Contact — a small alert lift, as the envelope itself is raised
   to show it (see .fox-accessory below). */
.pixel-fox[data-accessory="envelope"].is-looking .fox-head {
  transform: translateY(-1.5px) rotate(-2deg);
}

.pixel-fox.is-fluffy .fox-head {
  transform: rotate(9deg);
  transition: transform 0.5s ease;
}

@keyframes fox-look-around {
  0% { transform: rotate(0); }
  22% { transform: rotate(-11deg); }
  55% { transform: rotate(9deg); }
  80% { transform: rotate(-4deg); }
  100% { transform: rotate(0); }
}

.fox-head.is-looking-around {
  animation: fox-look-around 1.8s ease-in-out;
}


/* ---- eyes (blink) and ears (twitch) ---- */

.fox-eyes rect {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.09s ease, y 0.3s ease, height 0.3s ease;
}

/* Essays/Field Notes — eyes sit a little lower and noticeably
   thinner, like a focused, slightly narrowed reading gaze. Adjusts
   the actual SVG geometry (y/height) rather than `transform`, so it
   layers cleanly under the blink/sleep transforms above and below
   without fighting their own scaleY. */
.pixel-fox[data-accessory="book"] .fox-eyes rect {
  y: 17px;
  height: 2px;
}

.fox-eyes.is-blinking rect {
  transform: scaleY(0.12);
}

.pixel-fox.is-sleeping .fox-eyes rect {
  transform: scaleY(0.16);
  transition: transform 0.4s ease;
}

.fox-ear-left,
.fox-ear-right {
  transform-box: fill-box;
  transform-origin: bottom center;
  transition: transform 0.3s ease;
}

.fox-ear-left.is-twitching {
  transform: rotate(-14deg);
}

.fox-ear-right.is-twitching {
  transform: rotate(14deg);
}

.pixel-fox.is-lying .fox-ear-left { transform: rotate(-8deg); }
.pixel-fox.is-lying .fox-ear-right { transform: rotate(8deg); }

.pixel-fox.is-sleeping .fox-ear-left,
.pixel-fox.is-sleeping .fox-ear-right {
  transform: rotate(0) scaleY(0.9);
}


/* ---- Projects/About Me: round glasses + a tilted head ----
   Hidden/untilted by default, shown together only via .is-about (set
   on scroll into #projects or #about-me) — a quiet, quizzical
   "pausing to think" pose, replacing both the earlier squash/tail-
   curl attempt and the chin-propped paw that followed it. */

.fox-glasses {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity 0.4s ease;
}

.pixel-fox.is-about .fox-glasses {
  opacity: 1;
}

.fox-glasses-lens {
  fill: none;
  stroke: var(--fox-ink);
  stroke-width: 0.8;
}

/* Resting head tilt — kept, unchanged, through hover too (see the
   combined selector below), so hovering nudges the glasses (see the
   push keyframe below) without the head itself snapping to the
   plain look-up every other context uses. */

.pixel-fox.is-about.fox-head {
  transform: rotate(12deg);
}
.pixel-fox.is-about.is-looking .fox-head {
  transform: rotate(-16deg);
}

/* Hover — a quick, snappy "push the glasses back up the nose"
   nudge, distinct from the head's own hover reactions elsewhere. */
@keyframes fox-glasses-push {
  0% { transform: translateY(0); }
  30% { transform: translateY(-1.4px); }
  60% { transform: translateY(0.3px); }
  100% { transform: translateY(0); }
}

.pixel-fox.is-about.is-looking .fox-glasses {
  animation: fox-glasses-push 0.5s ease-out;
}

.fox-bowtie {
  opacity: 0;
  transition: opacity 0.4s ease;
}

.pixel-fox[data-accessory="envelope"] .fox-bowtie {
  opacity: 1;
}


/* ---- fluffy/confused reaction: fur tufts + a small pixel "?" ---- */

.fox-fluff circle {
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  transform: scale(0.4);
  transition: opacity 0.4s ease, transform 0.4s ease;
}

.pixel-fox.is-fluffy .fox-fluff circle {
  opacity: 1;
  transform: scale(1);
}

.fox-question {
  font-family: "Courier New", monospace;
  font-weight: 700;
  font-size: 9px;
  fill: var(--fox-shadow);
  text-anchor: middle;
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes fox-question-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-2.5px); }
}

.pixel-fox.is-fluffy .fox-question {
  opacity: 1;
  animation: fox-question-bob 1.3s ease-in-out infinite;
}


/* ---- sleep "z"s ---- */

.fox-zzz text {
  opacity: 0;
  font-family: "Courier New", monospace;
  font-weight: 700;
  fill: var(--fox-shadow);
  text-anchor: middle;
}

@keyframes fox-zzz-rise {
  0% { opacity: 0; transform: translateY(2px) scale(0.8); }
  25% { opacity: 0.85; }
  75% { opacity: 0.6; }
  100% { opacity: 0; transform: translateY(-9px) scale(1.1); }
}

.pixel-fox.is-sleeping .fox-zzz text {
  animation: fox-zzz-rise 2.6s ease-in-out infinite;
}

.pixel-fox.is-sleeping .fox-zzz text:nth-child(2) { animation-delay: 0.5s; }
.pixel-fox.is-sleeping .fox-zzz text:nth-child(3) { animation-delay: 1s; }


/* ---- click sparkles ---- */

.fox-sparkle {
  opacity: 0;
  font-family: "Courier New", monospace;
  font-weight: 700;
  font-size: 6px;
  fill: var(--fox-fur);
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes fox-sparkle-pop {
  0% { opacity: 0; transform: translateY(0) scale(0.4); }
  35% { opacity: 1; transform: translateY(-4px) scale(1); }
  100% { opacity: 0; transform: translateY(-9px) scale(0.7); }
}

.pixel-fox.is-hopping .fox-sparkle-a {
  animation: fox-sparkle-pop 0.5s ease-out;
}

.pixel-fox.is-hopping .fox-sparkle-b {
  animation: fox-sparkle-pop 0.5s ease-out 0.06s;
}


/* ---- accessory (per page/section context) ---- */

.fox-accessory {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.4s ease, opacity 0.5s ease;
}

/* Default hover reaction — subtle lift. Overridden per accessory
   below so each reads as its own small gesture rather than one
   generic nudge (see the matching .fox-head reactions above). */
.pixel-fox.is-looking .fox-accessory {
  transform: translateY(-1.5px);
}

/* Gallery — the camera is what lifts, up toward eye level. */
.pixel-fox[data-accessory="camera"].is-looking .fox-accessory {
  transform: translateY(-3.5px) rotate(-6deg);
}

/* Essays/Field Notes — the book stays put; the head looks down at
   it instead (see .fox-head above). */
.pixel-fox[data-accessory="book"].is-looking .fox-accessory {
  transform: translateY(0.5px);
}

/* Map — a small curious tilt, as if being consulted. */
.pixel-fox[data-accessory="compass"].is-looking .fox-accessory {
  transform: translateY(-1px) rotate(-8deg);
}

/* Contact — raised to show it. */
.pixel-fox[data-accessory="envelope"].is-looking .fox-accessory {
  transform: translateY(-3px) rotate(4deg);
}

.fox-accessory-camera,
.fox-accessory-book,
.fox-accessory-compass,
.fox-accessory-envelope {
  opacity: 0;
  transition: opacity 0.5s ease;
}

.pixel-fox[data-accessory="camera"] .fox-accessory-camera,
.pixel-fox[data-accessory="book"] .fox-accessory-book,
.pixel-fox[data-accessory="compass"] .fox-accessory-compass,
.pixel-fox[data-accessory="envelope"] .fox-accessory-envelope {
  opacity: 1;
}

/* Accessory is hidden (never mid-page/hover-reactive) once the fox
   is actually asleep or mid-stretch waking up — "placed aside"
   rather than staying visible on a curled-up, eyes-closed fox. It
   fades back in on its own once .is-idle resumes and the context's
   opacity rule above re-applies. */
.pixel-fox.is-sleeping .fox-accessory,
.pixel-fox.is-waking .fox-accessory {
  opacity: 0;
}


/* ---- speech / thought bubble ---- */

.fox-message {
  position: absolute;
  left: 50%;
  bottom: 100%;

  margin: 0 0 10px;
  padding: 6px 12px;

  width: max-content;
  max-width: 150px;

  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 3px;

  color: var(--ink);
  font-family: "Cormorant Garamond", "Noto Serif SC", serif;
  font-style: italic;
  font-size: 14px;
  line-height: 1.4;
  text-align: center;

  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 6px);

  transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.fox-message.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, 0);
}

/* The autonomous thought bubble — same element, quieter: smaller,
   slightly translucent, so it reads as a passing thought rather
   than a greeting aimed at the visitor. */
.fox-message.is-thought {
  font-size: 12px;
  padding: 4px 10px;
  max-width: 120px;
}

.fox-message.is-thought.is-visible {
  opacity: 0.92;
}


/* ---- reduced motion ---- */

@media (prefers-reduced-motion: reduce) {
  .fox-body,
  .fox-tail,
  .fox-head,
  .fox-question,
  .fox-zzz text,
  .fox-sparkle-a,
  .fox-sparkle-b,
  .pixel-fox.is-hopping .fox-rig,
  .pixel-fox.is-waking .fox-rig,
  .pixel-fox.is-about.is-looking .fox-glasses {
    animation: none !important;
  }

  .fox-rig,
  .fox-head,
  .fox-eyes rect,
  .fox-ear-left,
  .fox-ear-right,
  .fox-tail,
  .fox-message,
  .fox-accessory,
  .fox-glasses,
  .fox-fluff circle {
    transition-duration: 0.01ms !important;
  }
}


/* ---- mobile ---- */

@media (max-width: 760px) {
  .pixel-fox {
    right: 14px;
    /* max() keeps it clear of a phone's home-indicator gesture strip
       (env(safe-area-inset-bottom)) — without this, a tap here can
       get swallowed by the OS's own swipe-up gesture instead of
       ever reaching the page. */
    bottom: max(14px, env(safe-area-inset-bottom, 0px) + 8px);

    --fox-width: 42px;
    --fox-height: 46px;
  }

  .fox-message {
    max-width: 130px;
    font-size: 12px;
  }

  .fox-message.is-thought {
    max-width: 105px;
    font-size: 11px;
  }
}


/* ========================================
   AMBIENT MUSIC BUTTON (all pages)

   Built by audio.js — nothing hand-written into any page for it,
   same pattern as the fox and cursor. Two different layouts for two
   breakpoints, same <button> element throughout (audio.js never
   creates or moves it in the DOM based on screen size — this is CSS
   only, via the max-width query below):

   - Desktop: lives inside the top <header class="nav ...">, not a
     fixed corner — a plain icon sitting on the same row as the nav
     links, right after the last one (Contact, on the homepage), with
     the hamburger toggle immediately after it in turn on index.html.
     See ".nav nav" further up for how that row stays grouped flush
     right. No circle, no border, no fill — the note icon sits at the
     same visual weight as the plain-text links beside it.
   - Mobile: reverts to its own fixed bottom-left circle (Elvira's
     original placement, kept unchanged rather than following the nav
     — she asked for the desktop nav-icon treatment without carrying
     it over to mobile), independent of the header entirely.

   While playing, it "breathes" on both breakpoints — the same slow-
   pulse language as the hero's entrance and the scroll reveals
   elsewhere on the site — rather than an equalizer or spinner, so the
   active state reads as calm rather than busy. The two breakpoints
   use different keyframes (scale+opacity on desktop, since there's no
   background to glow against; scale+box-shadow ring on mobile, where
   the circle gives it something to glow against) — see
   music-toggle-breathe vs. music-toggle-breathe-fixed below.
======================================== */

.music-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;

  margin-left: 24px;
  padding: 2px;

  background: none;
  border: none;

  color: var(--ink);
  cursor: pointer;

  /* Same reasoning as .pixel-fox: skips the ~300ms tap-ambiguity
     delay some mobile browsers otherwise apply, and removes the
     grey tap-highlight flash. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;

  transition:
    color 0.35s ease,
    transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

.music-toggle:hover,
.music-toggle:focus-visible {
  color: var(--accent);
}

.music-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 3px;
}

.music-toggle:active {
  transform: scale(0.92);
}

.music-toggle-icon {
  width: 17px;
  height: 17px;
}

/* Playing state — quiet breathing pulse, not an equalizer. */

.music-toggle.is-playing {
  color: var(--accent);
  animation: music-toggle-breathe 3.6s ease-in-out infinite;
}

@keyframes music-toggle-breathe {
  0%, 100% {
    transform: scale(1);
    opacity: 0.82;
  }
  50% {
    transform: scale(1.14);
    opacity: 1;
  }
}

/* ---- mobile: back to the original fixed bottom-left circle ---- */

@media (max-width: 760px) {
  .music-toggle {
    position: fixed;
    left: 14px;
    bottom: max(14px, env(safe-area-inset-bottom, 0px) + 8px);
    z-index: 20;

    margin: 0;

    width: 42px;
    height: 42px;
    padding: 0;

    background: rgba(255, 250, 243, 0.72);
    border: 1px solid var(--line);
    border-radius: 50%;

    color: var(--muted);

    backdrop-filter: blur(6px);

    transition:
      color 0.4s ease,
      border-color 0.4s ease,
      background-color 0.4s ease,
      transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
      box-shadow 0.6s ease;
  }

  .music-toggle:hover,
  .music-toggle:focus-visible {
    color: var(--accent);
    border-color: rgba(155, 95, 68, 0.4);
    transform: scale(1.06);
  }

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

  .music-toggle:active {
    transform: scale(0.96);
  }

  .music-toggle-icon {
    width: 16px;
    height: 16px;
  }

  .music-toggle.is-playing {
    color: var(--accent);
    border-color: rgba(155, 95, 68, 0.45);
    background: rgba(255, 250, 243, 0.85);

    animation: music-toggle-breathe-fixed 4.2s ease-in-out infinite;
  }
}

@keyframes music-toggle-breathe-fixed {
  0%, 100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(185, 119, 106, 0.28);
  }
  50% {
    transform: scale(1.045);
    box-shadow: 0 0 0 7px rgba(185, 119, 106, 0);
  }
}

/* Placed after the max-width query above (not merged into it) so
   that reduced-motion always wins on top of it when both apply —
   otherwise a mobile device with reduced motion enabled would have
   the box-shadow-ring animation re-enabled by the later, equally-
   specific mobile rule. */
@media (prefers-reduced-motion: reduce) {
  .music-toggle {
    transition-duration: 0.01ms;
  }

  .music-toggle.is-playing {
    animation: none;
  }
}
