/* Typography and colours after sashabirukoff.com: Neue Haas Grotesk (its
   system twin, Helvetica Neue) at 24 / 14 / 12 px with a -0.1px track, one
   face for everything, no labels. Warm paper instead of white. */
:root {
  --bg: #f4f3ef;
  --fg: #1d1d1b;
  --mid: #7b7a74;
  --rule: #1a1a1a;
  --hair: rgba(17, 17, 17, 0.14);
  --hair-2: rgba(17, 17, 17, 0.08);
  --gutter: 20px;
  --col-left: 150px;
  --col-gap: 56px;
  --section-pad: 56px;
  --center-max: 480px;
  --portrait-size: 154px;
  --slot-ratio: 3 / 2;
  --sans: "Neue Haas Grotesk Text Pro", "Helvetica Neue", Helvetica, Inter, Arial, sans-serif;
  /* The wall's grid: the mark in the first column, the intro in the second;
     the plinth's timeline and widgets share the same columns. */
  --wall-cols: minmax(150px, 1fr) minmax(0, 2.7fr) minmax(0, 1.9fr) minmax(96px, 1fr);
  --wall-gap: 32px;
  --map-w: 300px; /* the map widget under the timeline */

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.3, 0.64, 1);
  --ease-book: cubic-bezier(0.65, 0, 0.2, 1);

}

/* Card grounds with contrasting ink, shared by text and canvas drawings. */
[data-palette="chalk"]    { --c-bg: #e9e8e4; --c-ink: #111111; }
[data-palette="paper"]    { --c-bg: #fbfaf6; --c-ink: #111111; }
[data-palette="grape"]    { --c-bg: #6a3fd8; --c-ink: #f1e8ff; }
[data-palette="lemon"]    { --c-bg: #f3d43b; --c-ink: #3b2f00; }
[data-palette="charcoal"] { --c-bg: #dce0e5; --c-ink: #111111; }
[data-palette="mint"]     { --c-bg: #a7abdd; --c-ink: #000000; }
[data-palette="rose"]     { --c-bg: #ef5b8f; --c-ink: #fff0f5; }
[data-palette="cream"]    { --c-bg: #9d8ca1; --c-ink: #ffffff; }
[data-palette="sky"]      { --c-bg: #9993b2; --c-ink: #ffffff; }
[data-palette="flame"]    { --c-bg: #81717a; --c-ink: #ffffff; }
[data-palette="moss"]     { --c-bg: #5f7d4c; --c-ink: #eef5e4; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 14px;
  line-height: 1.3;
  letter-spacing: -0.1px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--hair);
  transition: text-decoration-color 200ms ease;
}
a:hover { color: inherit; text-decoration-color: var(--fg); }

:focus-visible {
  outline: 1px solid var(--fg);
  outline-offset: 3px;
}
button { font: inherit; color: inherit; }

.topbar {
  padding: 18px var(--gutter) 0;
  max-width: 1680px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 24px;
}
.topnav {
  justify-self: center;
  font-size: 12px;
  letter-spacing: 0.01em;
}
.topnav a {
  text-decoration: none;
  padding: 0 6px;
  color: var(--fg);
}
.topnav a.active {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.topnav .sep { color: var(--mid); }
.topbar .spacer { justify-self: end; }

.topbar .backbtn {
  justify-self: start;
  color: var(--fg);
  text-decoration: none;
  font-size: 14px;
  line-height: 1;
  letter-spacing: 0.01em;
  cursor: pointer;
  padding: 12px;
  margin: -12px; /* a finger-sized hit area, drawn in the same spot */
}
.topbar .backbtn.is-hidden { visibility: hidden; }

.page {
  padding: 0 var(--gutter) 80px;
  max-width: 1680px;
  margin: 0 auto;
  transition: opacity 220ms ease, transform 220ms ease;
}
.page.home { padding-bottom: 0; }
.page.is-leaving {
  opacity: 0;
  transform: translateY(6px);
}
.page.is-entering {
  opacity: 0;
  transform: translateY(6px);
  transition: none;
}

.row {
  display: grid;
  grid-template-columns: var(--col-left) minmax(0, 1fr) minmax(0, 1.05fr);
  column-gap: var(--col-gap);
  align-items: start;
}

/* Yearscape sits in the right column beside the intro.
   Height is synced to .center via ResizeObserver in app.js. */
.section.first .row {
  align-items: start;
}
.section.first .timeline-panel {
  position: relative;
  display: block;
  min-height: 0;
  margin-top: 0;
  justify-content: stretch;
  overflow: hidden;
}
.section.first .timeline-panel .yearscape {
  max-width: none;
  width: 100%;
  height: 100%;
}

.section {
  padding-top: var(--section-pad);
  padding-bottom: var(--section-pad);
  scroll-margin-top: 24px;
}
.section.first {
  border-top: none;
  padding-top: clamp(40px, 6vw, 80px);
}

.left .title {
  font-size: 15px;
  line-height: 1.4;
  text-wrap: balance;
}
.left .year { font-size: 15px; line-height: 1.4; color: var(--fg); margin-top: 2px; }
.left .role {
  font-size: 12px;
  line-height: 1.5;
  color: var(--mid);
  margin-top: 14px;
  max-width: 130px;
}
.left .title-bold { font-weight: 500; }

/* Small facts under a project title. */
.meta {
  margin: 14px 0 0;
  font-size: 12px;
  line-height: 1.5;
  max-width: 150px;
}
.meta > div { margin-bottom: 8px; }
.meta > div:last-child { margin-bottom: 0; }
.meta dt { color: var(--mid); }
.meta dd { margin: 0; color: var(--fg); text-wrap: pretty; }

.yearscape {
  position: relative;
  width: 100%;
  max-width: 1100px;
  padding-top: 0;
  display: flex;
  align-items: stretch;
  gap: 0;
  user-select: none;
  --yearscape-detail-width: 220px;
  --yearscape-detail-gap: 20px;
  transition: gap 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
.yearscape.is-open {
  gap: var(--yearscape-detail-gap);
}
.yearscape-main {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
}
.yearscape-axis {
  position: relative;
  margin-bottom: 10px;
  height: 14px;
  flex: 0 0 auto;
  color: var(--mid);
  font-size: 11px;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
.yearscape-axis span {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  white-space: nowrap;
}
.yearscape-axis span:first-child {
  transform: translateX(0);
}
.yearscape-axis span:last-child {
  transform: translateX(-100%);
}
.yearscape-chart {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.yearscape-lanes {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
  gap: 10px;
  min-height: 0;
}
.yearscape-lane {
  min-height: 0;
}
.yearscape-track {
  position: relative;
  height: 32px;
  overflow: hidden;
}
.yearscape-track.is-stack-2 {
  height: 68px;
}
.yearscape-bar {
  position: absolute;
  inset-inline-start: var(--start);
  width: min(
    max(calc(var(--end) - var(--start)), 48px),
    calc(100% - var(--start))
  );
  top: calc(var(--row, 0) * 36px);
  height: 32px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  box-sizing: border-box;
  background: transparent;
  color: var(--fg);
  box-shadow: inset 0 0 0 1px var(--fg);
  overflow: hidden;
  cursor: pointer;
  transition:
    opacity 160ms ease,
    background 160ms ease,
    color 160ms ease,
    box-shadow 200ms ease;
  z-index: 1;
}
.yearscape-bar:hover {
  z-index: 3;
  background: rgba(17, 17, 17, 0.07);
}
.yearscape-bar.is-selected {
  z-index: 4;
  background: var(--fg);
  color: var(--bg);
  box-shadow: none;
}
.yearscape.is-open .yearscape-bar:not(.is-selected) {
  opacity: 0.42;
}
.yearscape-bar-title {
  font-size: 12px;
  line-height: 1.2;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  pointer-events: none;
}
.yearscape-detail {
  flex: 0 0 auto;
  width: 0;
  align-self: stretch;
  box-sizing: border-box;
  background: var(--bg);
  overflow: hidden;
  transition: width 320ms cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}
.yearscape.is-open .yearscape-detail {
  width: var(--yearscape-detail-width);
  pointer-events: auto;
}
.yearscape-detail-inner {
  position: relative;
  width: var(--yearscape-detail-width);
  box-sizing: border-box;
  padding-inline-start: 12px;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.yearscape-detail-close {
  appearance: none;
  position: absolute;
  top: 0;
  inset-inline-end: 0;
  border: 0;
  background: transparent;
  color: var(--mid);
  font: inherit;
  font-size: 18px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
}
.yearscape-detail-close:hover,
.yearscape-detail-close:focus-visible {
  color: var(--fg);
  outline: none;
}

.yearscape-detail-body {
  color: var(--fg);
  font-size: 13px;
  line-height: 1.65;
  overflow: auto;
  min-height: 0;
  flex: 1 1 auto;
  padding-inline-end: 24px;
}
.yearscape-detail-body p {
  margin: 0 0 0.85em;
  text-wrap: pretty;
}
.yearscape-detail-body p:last-child {
  margin-bottom: 0;
}

@media (max-width: 900px) {
  .section.first .row {
    grid-template-columns: 1fr;
    row-gap: 18px;
  }
  .section.first .timeline-panel {
    position: static;
    margin-top: 0;
    height: auto !important;
  }
  .section.first .timeline-panel .yearscape {
    position: static;
    height: auto;
    min-height: 240px;
  }
  .yearscape {
    max-width: none;
    flex-direction: column;
  }
  .yearscape.is-open {
    gap: 12px;
  }
  .yearscape-main {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .yearscape-axis,
  .yearscape-lanes {
    min-width: 520px;
  }
  .yearscape-lane {
    min-height: 0;
  }
  .yearscape-bar {
    height: 30px;
    padding: 0 10px;
  }
  .yearscape-bar-title {
    font-size: 11px;
  }
  .yearscape-detail {
    width: 100%;
    max-height: 0;
    transition: max-height 320ms ease;
  }
  .yearscape-detail-inner {
    width: 100%;
    padding-inline-start: 0;
    padding-top: 0;
  }
  .yearscape.is-open .yearscape-detail {
    max-height: 420px;
  }
  .yearscape.is-open .yearscape-detail-inner {
    padding-top: 0;
  }
}

.center { max-width: var(--center-max); }
.center .tags { font-size: 14px; margin-bottom: 28px; }
.center .meta {
  font-size: 14px;
  margin-bottom: 24px;
  white-space: pre-line;
}
.center p,
.prose p {
  font-size: 14px;
  line-height: 1.7;
  margin: 0 0 1em;
  text-wrap: pretty;
}
.center p:last-child,
.prose p:last-child { margin-bottom: 0; }

.btn {
  display: inline-block;
  margin-top: 12px;
  padding: 9px 18px;
  border: 1px solid var(--fg);
  background: transparent;
  text-decoration: none;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  transition: background 200ms ease, color 200ms ease;
}
.btn:hover { background: var(--fg); color: var(--bg); }

.right { width: 100%; }

.carousel { width: 100%; }
.carousel-slot {
  width: 100%;
  aspect-ratio: var(--slot-ratio);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  overflow: hidden;
  background: transparent;
}
.carousel-slot img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  outline: 1px solid oklch(0 0 0 / 0.1);
}
.carousel-slot.empty { cursor: default; }
.counter {
  margin-top: 10px;
  font-size: 12px;
  color: var(--mid);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.ascii-portrait {
  position: relative;
  display: inline-block;
  line-height: 0;
  margin-inline-start: auto;
}
.right { display: flex; justify-content: flex-end; }

.ascii-layer {
  font-family: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  line-height: 1;
  letter-spacing: 0;
  margin: 0;
  padding: 0;
  white-space: pre;
  font-weight: 400;
  pointer-events: none;
  user-select: none;
}
.ascii-portrait .ascii-layer:not(:first-child) {
  position: absolute;
  top: 0;
  inset-inline-start: 0;
}
.layer-portrait { color: #0a0806; }
.layer-rain { color: #1c2a36; }

.bio p {
  margin: 0 0 1em;
  text-wrap: pretty;
}
.bio .group { margin-bottom: 22px; }
.bio .group:last-child { margin-bottom: 0; }
.bio .group-label {
  display: block;
  color: var(--mid);
  margin-bottom: 4px;
}
.bio .name-label { font-size: 15px; margin-top: 0; }

/* ---------- The wall (home) ---------- */

/* The first screen is one wall. Along the top, the way a museum writes a
   room's label: my name in the top-left corner and the intro in a measured
   column beside it. The cards hang in the middle (pile.js lays them out in
   .stage-inner and motion.js moves them). A four-column grid on desktop,
   one column on a phone, where the ring gives way to the stack. The links
   sit in the bottom-right corner of the page, answering the name. */
.page {
  padding: 0 var(--gutter);
  max-width: none;
  margin: 0;
}
.pile-section {
  padding-top: 0;
  padding-bottom: 0;
}
.stage {
  position: relative;
  width: 100%;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  --desc-w: 416px; /* the open card's text width; pile.js keeps it current */
}
.stage-inner {
  position: relative;
  flex: 1 1 auto;
  min-height: 380px;
  order: 1;
  margin-bottom: 18px;
}
.wall {
  position: relative;
  z-index: 2;
  margin: 0;
  animation: wall-in 1000ms var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 110ms + 80ms);
}
@keyframes wall-in {
  from { opacity: 0; filter: blur(4px); }
  to   { opacity: 1; filter: blur(0); }
}
.wall-tl {
  order: 0;
  --i: 0;
  display: grid;
  grid-template-columns: var(--wall-cols);
  column-gap: var(--wall-gap);
  align-items: start;
  padding-top: 20px;
}
.name {
  grid-column: 1;
  font-size: 14px;
  line-height: 1.3;
  color: var(--fg);
  text-decoration: none;
  white-space: nowrap;
  padding-top: 5px;
}
.intro {
  grid-column: 2;
  margin: 0;
  max-width: 640px;
  font-size: 24px;
  line-height: 1.2;
  letter-spacing: -0.8px;
  font-weight: 400;
  text-wrap: pretty;
}
/* A ring with a dot before a name, the way sashabirukoff.com marks "logo,
   brand, graphic": coloured by [data-palette], or Yarado's red. */
.dot-link {
  text-decoration: none;
  white-space: nowrap;
}
/* An underline that slides in from the left on hover and out to the right:
   a 1px line painted as a background whose width grows, anchored left
   while it grows and right while it shrinks. */
.ul,
.foot-links a,
a.tl-what {
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 100% 100%;
  background-size: 0% 1px;
  transition: background-size 340ms var(--ease-out);
}
.dot-link:hover .ul,
.foot-links a:hover,
a.tl-what:hover {
  background-position: 0% 100%;
  background-size: 100% 1px;
}
.ul { padding-bottom: 1px; }
.dot {
  display: inline-block;
  width: 15px;
  height: 15px;
  margin-right: 5px;
  vertical-align: -1px;
  border-radius: 50%;
  background:
    radial-gradient(circle at center, var(--c-bg) 0 30%, var(--bg) 34% 58%, var(--c-bg) 62% 100%);
  box-shadow: inset 0 0 0 1px rgba(17, 17, 17, 0.06);
  transition: transform 300ms var(--ease-spring);
}
.dot-link:hover .dot { transform: scale(1.12); }
.dot-yarado { --c-bg: #b8413c; }
.dot[data-palette="cream"] { --c-bg: #8f7d93; } /* a shade deeper than the card, so the ring reads on paper */
/* ---------- The timeline ---------- */

/* Under the cards, in the middle, like pengzhe.ng's list of work: what,
   then the years in grey. No rules. The map of where I am sits beneath. */
.plinth {
  padding: 8px 0 72px;
  text-align: center;
}
.tl-list {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  max-width: 720px;
}
.tl-row {
  display: flex;
  justify-content: center;
  align-items: baseline;
  flex-wrap: wrap;
  column-gap: 12px;
  padding: 7px 0;
  font-size: 20px;
  line-height: 1.3;
  letter-spacing: -0.3px;
}
.tl-what { color: var(--fg); text-decoration: none; text-wrap: balance; }
.tl-when { color: var(--mid); font-variant-numeric: tabular-nums; }
.wall-map {
  width: var(--map-w);
  max-width: 100%;
  margin: 44px auto 0;
  --i: 1;
}

/* Widgets, after iOS: rounded, self-contained, sized by their slot; the
   type inside scales with the widget (container units). */
.widget {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 20px;
  overflow: hidden;
  background: #fff;
  container-type: inline-size;
  box-shadow:
    0 0 0 1px rgba(17, 17, 17, 0.06),
    0 18px 40px -20px rgba(17, 17, 17, 0.22);
  -webkit-user-select: none;
  user-select: none;
}
/* The place: Apple-Maps-like rendering of Utrecht, fading to white at the
   bottom under the name, a blue dot where I am. */
.widget-map .map-img {
  position: absolute;
  inset: -2%;
  background: #eef3f5 url("/images/widgets/utrecht.webp") center / cover no-repeat;
}
.widget-map::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 58%;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.86) 62%, #fff 100%);
  pointer-events: none;
}
.map-pin {
  position: absolute;
  left: 50%;
  top: 44%;
  width: 5.5cqw;
  height: 5.5cqw;
  margin: -2.75cqw 0 0 -2.75cqw;
  border-radius: 50%;
  background: #1a7cf5;
  box-shadow: 0 0 0 0.9cqw #fff, 0 0.5cqw 1.6cqw rgba(0, 40, 90, 0.35);
  z-index: 1;
}
.map-pin::after {
  content: "";
  position: absolute;
  inset: -3cqw;
  border-radius: 50%;
  background: rgba(26, 124, 245, 0.28);
  animation: pin-pulse 2.6s ease-out infinite;
}
@keyframes pin-pulse {
  0%   { transform: scale(0.4); opacity: 0.9; }
  100% { transform: scale(1.6); opacity: 0; }
}
.map-caption {
  position: absolute;
  left: 7%;
  right: 7%;
  bottom: 8%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 0.6cqw;
  color: #1c1c1a;
}
.map-title {
  font-size: 8.4cqw;
  line-height: 1.1;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.map-sub {
  font-size: 5.6cqw;
  line-height: 1.2;
  color: #7b7a74;
}
/* ---------- Footer ---------- */

.foot {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  padding: 8px 0 20px;
  font-size: 14px;
  line-height: 20px;
}
.foot-links { display: flex; align-items: baseline; gap: 10px; }
.foot-links a { color: var(--fg); }
.foot-links .sep { color: var(--mid); }

/* A card: its box (width, height) and pose (transform) are set by pile.js
   every frame; the face inside carries the hover lift and the entrance. */
.pcard {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 228px;
  height: 288px;
  cursor: pointer;
  color: var(--c-ink);
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  will-change: transform;
  outline: none;
  --open: 0;   /* 0 at rest, 1 at the open size */
  --detail: 0; /* the blurb's presence */
  --desc-h: 160px; /* the blurb's height at the open width; measured by pile.js */
}
.pcard.is-open { cursor: default; }
.pcard:focus-visible .pcard-face {
  box-shadow:
    0 0 0 1px rgba(17, 17, 17, 0.06),
    0 0 0 3px var(--bg),
    0 0 0 4px var(--fg);
}
.pcard-face {
  position: absolute;
  inset: 0;
  border-radius: 16px;
  background: var(--c-bg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 16px;
  --fall: 0; /* 1 while the card is still in the air on load (pile.js) */
  /* A hairline edge and no drop shadow at rest; while falling in, a soft
     one beneath, so the card reads as above the wall until it lands. */
  box-shadow:
    0 0 0 1px rgba(17, 17, 17, 0.06),
    0 calc(var(--fall) * 22px) calc(var(--fall) * 36px) rgba(17, 17, 17, calc(var(--fall) * 0.16));
}
.pcard-visual {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  border-radius: 8px;
  overflow: hidden;
}
.pcard-visual canvas,
.pcard-visual img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.pcard-visual img {
  object-fit: cover;
  object-position: center;
  -webkit-user-drag: none;
  user-drag: none;
}
.pcard.has-gallery.is-stack .pcard-visual img { object-fit: contain; }
.pcard.has-gallery.is-open .pcard-visual img,
.pcard.has-gallery.is-front .pcard-visual img {
  /* The new image has its final size from the first frame. Only its clip
     changes; a shrinking frame may briefly show the neutral mount above it. */
  top: auto;
  height: var(--photo-h);
  object-fit: contain;
  object-position: center bottom;
}
.pcard.is-open.has-gallery .pcard-visual,
.pcard.is-front.has-gallery .pcard-visual { cursor: pointer; }
.pcard-body {
  flex: 0 0 auto;
  margin-top: 12px;
  min-height: 0;
}
.pcard-year {
  display: block;
  font-size: 12px;
  line-height: 1.4;
  opacity: 0.75;
  margin-bottom: 4px;
  font-variant-numeric: tabular-nums;
}
.pcard-title {
  display: block;
  font-size: calc(24px + var(--open) * 6px);
  line-height: 1.12;
  font-weight: 500;
  letter-spacing: -0.005em;
  white-space: pre-line;
  text-wrap: balance;
}
/* The blurb is set at the open width from the start, so its lines never
   re-wrap while the card grows; the card makes room for it in step with
   its own growth (--open) and it fades in a beat later (--detail). */
.pcard-desc {
  width: var(--desc-w);
  max-height: calc(var(--open) * var(--desc-h));
  overflow: hidden;
  opacity: var(--detail);
  transform: translateY(calc((1 - var(--detail)) * 8px));
}
.pcard-desc p {
  margin: 10px 0 0;
  font-size: 13.5px;
  line-height: 1.55;
  opacity: 0.88;
  text-wrap: pretty;
}
.pcard-more {
  display: inline-block;
  margin-top: 10px;
  font-size: 13px;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
  transition: text-decoration-color 200ms ease;
}
.pcard-more:hover { text-decoration-color: currentColor; }

/* ?debug: the springs' values, painted every frame by pile.js. */
.motion-debug {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 1000;
  min-width: 250px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.94);
  color: #111;
  font: 11px/1.5 ui-monospace, "SF Mono", Menlo, monospace;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
  pointer-events: none;
}
.motion-debug div { display: flex; justify-content: space-between; gap: 12px; }
.motion-debug span { color: #777; }

body.no-scroll { overflow: hidden; }


/* ---------- Photography ---------- */

.gallery-section {
  padding-top: var(--section-pad);
  padding-bottom: var(--section-pad);
}
.gallery {
  column-count: 3;
  column-gap: 16px;
}
.gallery-item {
  margin: 0 0 16px;
  break-inside: avoid;
  display: block;
}
.gallery-item img {
  width: 100%;
  height: auto;
  display: block;
  cursor: pointer;
  outline: 1px solid oklch(0 0 0 / 0.1);
  transition: opacity 200ms ease;
}
.gallery-item img:hover {
  opacity: 0.82;
}

@keyframes lightbox-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes lightbox-image-in {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(20, 20, 20, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 32px;
  animation: lightbox-fade-in 180ms ease-out;
}
.lightbox-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  max-width: 100%;
  max-height: 100%;
}
.lightbox-close {
  appearance: none;
  position: absolute;
  top: 16px;
  inset-inline-end: 16px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
  font: inherit;
  font-size: 22px;
  line-height: 1;
  padding: 6px 10px;
  cursor: pointer;
}
.lightbox-nav {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
  font: inherit;
  font-size: 18px;
  line-height: 1;
  padding: 12px 14px;
  cursor: pointer;
  flex: 0 0 auto;
}
.lightbox-close:hover,
.lightbox-nav:hover {
  background: rgba(255, 255, 255, 0.12);
}
.lightbox-counter {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, 0.7);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.lightbox img {
  max-width: min(100%, calc(100vw - 160px));
  max-height: calc(100vh - 64px);
  object-fit: contain;
  display: block;
  outline: 1px solid oklch(1 0 0 / 0.1);
  animation: lightbox-image-in 220ms ease-out;
}

/* ---------- Motion preferences ---------- */

@media (prefers-reduced-motion: reduce) {
  .page,
  .yearscape,
  .yearscape-main,
  .yearscape-bar,
  .yearscape-detail {
    transition: none;
  }
  .wall { animation: none; }
  .map-pin::after { animation: none; opacity: 0; }
  .dot { transition: none; }
  .lightbox, .lightbox img { animation: none; }
  .pcard-visual img { transition: none; }
}

/* ---------- Responsive ---------- */

@media (max-width: 1100px) {
  .gallery { column-count: 2; }
}

@media (max-width: 900px) {
  /* The wall folds to two columns: mark and links on one line, the intro
     across, the aside beneath. The ring keeps its box of its own below;
     pile.js scales it to the width and sets the box's height per state. */
  :root { --wall-gap: 24px; }
  .pile-section { margin: 0 calc(-1 * var(--gutter)); padding-bottom: 0; overflow-x: clip; }
  .stage {
    min-height: 0;
    height: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 0 var(--gutter);
  }
  .wall-tl {
    grid-template-columns: 1fr;
    row-gap: 16px;
    padding-top: 18px;
  }
  .name { grid-column: 1; grid-row: 1; padding-top: 0; }
  .intro { grid-column: 1; grid-row: 2; max-width: 560px; }
  .wall-map { width: min(62%, 300px); margin-top: 36px; }
  .wall-map .widget { aspect-ratio: 1; }
  .stage-inner {
    order: 1;
    flex: 0 0 auto;
    min-height: 0;
    width: calc(100% + 2 * var(--gutter));
    margin: 8px calc(-1 * var(--gutter)) 0;
    height: 420px; /* pile.js sets the real height from the width and state */
  }
  .plinth { padding: 28px 0 56px; }}

@media (max-width: 760px) {
  /* On a phone the ring gives way to a stack (pile.js): the front card
     shows its blurb, sticks to the finger that presses it, and thrown
     sideways brings the next one up. The first screen holds the label,
     the stack and the caption; the plinth follows. */
  .row {
    grid-template-columns: 1fr;
    row-gap: 18px;
  }
  .left .title { display: inline; }
  .left .year { display: inline; margin-inline-start: 12px; color: var(--mid); }
  .left .role { display: block; margin-top: 14px; }
  .meta { max-width: none; }
  .right { justify-content: flex-start; }
  .ascii-portrait { margin-inline-start: 0; }
  .center { max-width: none; }
  .topbar { grid-template-columns: 1fr 1fr; }
  .topnav { justify-self: end; }
  .topbar .spacer { display: none; }
  .gallery { column-count: 1; }

  .stage {
    height: 100svh;
    padding: 0 var(--gutter);
  }
  .wall-tl {
    row-gap: 14px;
    padding-top: 16px;
  }
  .intro {
    font-size: 20px;
    line-height: 1.22;
    letter-spacing: -0.5px;
  }
  .dot { width: 13px; height: 13px; margin-right: 4px; }
  .stage-inner { margin: 6px calc(-1 * var(--gutter)) 16px; touch-action: pan-y; }
  .pcard.is-stack { cursor: default; }
  .pcard.is-front { cursor: grab; touch-action: none; }
  .pcard.is-dragging { cursor: grabbing; }
  .pcard.is-stack .pcard-title { font-size: 24px; white-space: normal; }
  .pcard.is-stack .pcard-year { font-size: 11px; }
  .pcard.is-stack .pcard-desc p { margin-top: 8px; font-size: 12.5px; line-height: 1.45; }
  .pcard.is-stack .pcard-more { margin-top: 8px; font-size: 12px; }

  .wall-map { width: min(64%, 260px); margin-top: 30px; }
  .plinth { padding: 28px 0 40px; }
  .tl-row { font-size: 17px; column-gap: 10px; padding: 6px 0; }
  .widget { border-radius: 22px; }
  .widget-map::after { height: 52%; }
  .map-caption { bottom: 7%; }
  .map-title { font-size: 9.5cqw; }
  .map-sub { font-size: 6cqw; }
  .foot { padding: 4px 0 24px; }

  /* Lightbox: the photo takes the whole width, the arrows sit beneath it. */
  .lightbox { padding: 12px; }
  .lightbox-stage {
    flex-wrap: wrap;
    gap: 12px;
    width: 100%;
  }
  .lightbox img {
    order: 0;
    flex: 0 0 100%;
    max-width: 100%;
    max-height: calc(100vh - 140px);
    max-height: calc(100dvh - 140px);
    object-fit: contain;
  }
  .lightbox-prev { order: 1; }
  .lightbox-next { order: 2; }
  .lightbox-nav { padding: 12px 22px; }
  .lightbox-close { padding: 8px 12px; }
}
