:root {
  --text: #f4ecd8;
  --text-soft: #c9bedc;
  --line: #e9dfc8;
  --paper: #efe3c8;
  --ink: #33281c;
  --string: #b8322a;
  --item-min: 170px;
  --drift: 1;
  --index-width: clamp(280px, 26vw, 400px);
  --index-bg: transparent;
  --index-ink: var(--text);
}

[hidden] { display: none !important; }

html, body {
  height: auto;
  min-height: 100%;
  overflow-x: clip;
  overflow-y: auto;
}

.spread {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--item-min), 1fr));
  grid-auto-flow: dense;
  gap: clamp(3rem, 6vw, 6rem) clamp(2rem, 4.5vw, 4.5rem);
  padding: clamp(2rem, 5vw, 4.5rem) clamp(1.25rem, 4vw, 4rem) 6rem;
}

.item {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: var(--align);
  cursor: pointer;
  transform: translate(calc(var(--x) * var(--drift)), calc(var(--y) * var(--drift))) rotate(var(--r));
  transition: transform 0.25s ease;
}

.item-cell {
  min-width: 0;
  translate: var(--px, 0) var(--py, 0);
  transition: translate 0.9s cubic-bezier(0.22, 1.2, 0.36, 1) var(--pd, 0ms);
  scroll-margin-top: 1.5rem;
}

.item-cell > .item {
  width: 100%;
}

.item-cell.big {
  grid-column: span 2;
  grid-row: span 2;
}

.item:hover,
.item:focus-visible {
  z-index: 3;
  transform: translate(calc(var(--x) * var(--drift)), calc(var(--y) * var(--drift) - 6px)) rotate(0deg) scale(1.05);
}

.item:focus-visible {
  outline: 2px dashed var(--line);
  outline-offset: 6px;
}

.item-art {
  flex: 1;
  display: block;
  width: 100%;
  min-height: 0;
  aspect-ratio: 1;
  object-fit: contain;
  filter: drop-shadow(0 8px 8px rgba(5, 3, 12, 0.55));
}

.item-title {
  display: block;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.1;
}

.item-name {
  margin-top: 0.15rem;
  overflow: hidden;
  color: var(--text-soft);
  font-size: 0.82rem;
  line-height: 1.15;
}

.item-cell.big .item-title { font-size: 1.35rem; }

.spread {
  margin-left: var(--index-width);
}

.index {
  position: fixed;
  z-index: 4;
  top: 0;
  left: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  width: var(--index-width);
  padding: 1.75rem 1.75rem 0;
  background: var(--index-bg);
  color: var(--index-ink);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.95rem;
}

.index-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0 0.35rem 0.7rem;
  border-bottom: 1px solid var(--index-ink);
}

.index-search-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.index-search input {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  outline: 0;
  background: none;
  color: inherit;
  font: inherit;
  appearance: none;
}

.index-search input::placeholder {
  color: var(--index-ink);
  opacity: 1;
}

.index-search input::-webkit-search-cancel-button { display: none; }
.index-search:focus-within { border-bottom-width: 2px; padding-bottom: calc(0.7rem - 1px); }

.index-search-clear {
  display: flex;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}
.index-search-clear[hidden] { display: none; }
.index-search-clear svg { width: 18px; height: 18px; }
.index-search-clear:not([hidden]) + .index-search-icon { display: none; }

.index-search svg {
  flex: none;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

.index-groups {
  flex: 1;
  min-height: 0;
  margin-right: -0.9rem;
  padding: 0 0.9rem 2rem 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-color: var(--text-soft) transparent;
  scrollbar-width: thin;
}

.index-group { margin-top: 2rem; }

.index-heading {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--index-ink);
  font-size: inherit;
  font-weight: 400;
}

.index-list {
  margin: 0.4rem 0 0;
  padding: 0;
  list-style: none;
}

.index-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  min-height: 39px;
  padding: 0.45rem 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.index-row:hover .index-title,
.index-row:focus-visible .index-title {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.index-row:focus-visible { outline: 1px dashed var(--index-ink); }

.index-art {
  flex: none;
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.index-title {
  flex: 1;
  min-width: 0;
}

.index-row.is-active .index-title {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The title keeps its space so nothing jumps while the name moves up. */
.spread.has-open .item-cell:not(.is-open) .item-title {
  order: 1;
  visibility: hidden;
}

.spread.has-open .item-cell:not(.is-open) .item-name { color: var(--text); }

.item-cell.is-open { z-index: 5; position: relative; }

.item-hero {
  display: block;
  grid-column: 1 / -1;
  width: 100%;
  height: auto;
  object-fit: cover;
}

.item-cell:not(.is-open) .item-hero { display: none; }

.item-video { position: relative; }

.item-video img,
.item-video iframe,
.video-play {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.item-video img { object-fit: cover; }

.video-play {
  position: relative;
  padding: 0;
  background: none;
  cursor: pointer;
}

.video-play svg {
  position: absolute;
  top: 50%;
  left: 50%;
  width: clamp(48px, 9%, 72px);
  translate: -50% -50%;
  transition: scale 0.2s ease;
}

.video-play svg circle { fill: rgba(10, 6, 20, 0.55); stroke: var(--text); stroke-width: 2; }
.video-play svg path { fill: var(--text); }
.video-play:hover svg,
.video-play:focus-visible svg { scale: 1.08; }
.video-play:focus-visible { outline: 2px dashed var(--line); outline-offset: 4px; }

.item-cell.is-open {
  translate: none;
  transition: none;
}

.item-cell.is-open > .item-inner {
  position: fixed;
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  scrollbar-color: var(--text-soft) transparent;
  scrollbar-width: thin;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: start;
  width: min(820px, var(--stage, 820px));
}

.item-cell.is-open .item,
.spread.is-grid .item-cell.is-open .item {
  padding-top: 0;
  border-top: 0;
  cursor: default;
}

.item-cell.is-open .item-title {
  display: block;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
}

.item-cell.is-open .item-name { font-size: 1rem; }

.item-cell.is-open .index-detail {
  padding-top: 0;
  border-bottom: 0;
}

.spread.has-open .item-cell:not(.is-open) { opacity: 0.2; transition: opacity 0.3s ease, translate 0.9s cubic-bezier(0.22, 1.2, 0.36, 1) var(--pd, 0ms); }
.spread.is-grid.has-open .item-cell:not(.is-open) { opacity: 0.12; }

.detail-close {
  display: block;
  margin-left: auto;
  padding: 0.2rem 0;
  border: 0;
  border-bottom: 1px solid currentColor;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

@media (max-width: 640px) {
  .item-cell.is-open > .item-inner { grid-template-columns: minmax(0, 1fr); }
}

.spread.is-river .item-cell:not(.is-open) > .item {
  animation: pond-bob var(--bob, 3s) ease-in-out var(--bob-delay, 0s) infinite alternate;
}

@keyframes pond-bob {
  to { translate: 0 -6px; }
}

.item-cell.is-open > .item {
  text-align: left;
  transform: none;
}

.index-detail {
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  padding: 0.5rem 0 1.25rem;
  border-bottom: 1px solid var(--index-ink);
  font-size: 0.85rem;
  line-height: 1.5;
}

.index-detail p {
  margin: 0.6rem 0 0;
  white-space: pre-line;
}

.index-detail h3 {
  margin: 1.1rem 0 0;
  font-size: 0.95rem;
  font-weight: 500;
}

.index-detail a {
  color: inherit;
  overflow-wrap: anywhere;
}

.detail-photo {
  display: block;
  width: min(180px, 70%);
  aspect-ratio: 1;
  margin-top: 1.1rem;
  object-fit: cover;
}

.detail-meta { color: var(--text-soft); }

.detail-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
}

.detail-links svg {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
}

.detail-links svg .dot { fill: currentColor; stroke: none; }

.detail-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0.6rem 0 0;
  padding: 0;
  list-style: none;
}

.view-switch {
  display: flex;
  gap: 1.25rem;
  margin-top: 1rem;
}

.view-switch button {
  padding: 0.2rem 0;
  border: 0;
  border-bottom: 1px solid transparent;
  background: none;
  color: var(--text-soft);
  font: inherit;
  cursor: pointer;
}

.view-switch button[aria-pressed='true'] {
  border-bottom-color: currentColor;
  color: var(--index-ink);
}

.item-meta { display: none; }

/* Grid view: a ruled catalogue page, one specimen per cell. */
.spread:not(.is-grid) {
  --drift: 0;
  display: block;
}

.spread:not(.is-grid) .item-cell {
  position: absolute;
}

.spread.is-grid {
  --rule: rgba(233, 223, 200, 0.4);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--rule);
  border-left: 1px solid var(--rule);
}

.spread.is-grid .item-cell {
  min-height: 15rem;
  padding: 0.8rem 0.7rem 1rem;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.spread.is-grid .item {
  height: 100%;
  padding: 0;
  text-align: center;
  transform: none;
}

.spread.is-grid .item-title {
  order: 0;
  min-height: 2.2em;
  font-size: 0.95rem;
}

.spread.is-grid .item-meta {
  order: 1;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  margin: 0.45rem 0 0.8rem;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  color: var(--text-soft);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.62rem;
  line-height: 1.2;
}

.spread.is-grid .item-meta span {
  padding: 0.25rem 0.4rem;
  overflow-wrap: break-word;
}

.spread.is-grid .item-meta span + span { border-left: 1px solid var(--rule); }
.spread.is-grid .item-name { display: none; }

.spread.is-grid .item-art {
  order: 2;
  flex: none;
  width: 82%;
  margin: auto;
}

.spread.is-grid .item-cell.is-open .item-meta { display: none; }
.spread.is-grid .item-cell.is-open .item-name { display: block; }

.spread.is-grid.has-open .item-cell:not(.is-open) .item-title { order: 0; }

.spread.is-grid .item-cell.big:not(.is-open) {
  grid-column: auto;
  grid-row: auto;
}

.index-empty { margin: 2rem 0 0; }

@media (max-width: 800px) {
  :root { --drift: 0.25; }
  .spread { margin-left: 0; }

  .index {
    position: relative;
    z-index: 2;
    width: auto;
    padding: 3.75rem 1.25rem 0;  /* clears the back link */
  }

  .index-groups { max-height: 45dvh; }

  .index-menu {
    position: absolute;
    top: 1rem;
    left: 0.85rem;
    display: flex;
    padding: 0.4rem;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
  }
  .index-menu svg {
    width: 26px;
    height: 26px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linecap: round;
  }
  /* The list unfolds and folds away smoothly rather than snapping. */
  .index { transition: padding-bottom 0.45s cubic-bezier(0.22, 1, 0.36, 1); }
  .index.is-collapsed { padding-bottom: 0; }
  .index-body {
    display: grid;
    grid-template-rows: 1fr;
    transition: grid-template-rows 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .index-body-inner {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    opacity: 1;
    translate: 0 0;
    transition: opacity 0.35s ease, translate 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .index.is-collapsed .index-body { grid-template-rows: 0fr; }
  .index.is-collapsed .index-body-inner { opacity: 0; translate: 0 -10px; visibility: hidden; transition: opacity 0.25s ease, translate 0.45s ease, visibility 0s linear 0.45s; }
}

@media (min-width: 801px) {
  .index-menu { display: none; }
}

@media (max-width: 560px) {
  :root { --item-min: 130px; --drift: 0.25; }
  .item-cell.big { grid-row: span 1; }
}

@media (prefers-reduced-motion: reduce) {
  .item,
  .item-cell { transition: none; }
  .spread.is-river .item-cell:not(.is-open) > .item { animation: none; }
}

/* River: the page stops scrolling and the projects stream past instead. */
.river-lock,
.river-lock body { overflow: hidden; }

.spread.is-river .item-cell:not(.is-open) { opacity: 0.6; }
.spread.is-river-live .item-cell:not(.is-open) { transition: opacity 0.3s ease; }

.spread:not(.is-grid) .item-cell.is-open > .item-inner {
  width: min(600px, calc(var(--stage, 600px) * 0.62));
}

/* Wordy profiles spread out sideways: a wider card, a narrower artwork column
   and the text set in two columns so it isn't one long scroll. */
.item-cell.is-open > .item-inner.is-long,
.spread:not(.is-grid) .item-cell.is-open > .item-inner.is-long {
  grid-template-columns: minmax(0, 3fr) minmax(0, 8fr);
  width: min(980px, calc(var(--stage, 980px) * 0.86));
}

.item-inner.is-long .index-detail {
  columns: 2 13rem;
  column-gap: clamp(1.5rem, 2.5vw, 2.5rem);
}

.item-inner.is-long .detail-close,
.item-inner.is-long .detail-photo { column-span: all; }
.item-inner.is-long .index-detail h3 { break-after: avoid; }
.item-inner.is-long .detail-links { break-inside: avoid; }

.item-inner.is-long .item-title {
  font-size: clamp(1.2rem, 1.9vw, 1.7rem);
  overflow-wrap: anywhere;
}

/* Hero as the centrepiece: title, notes and people scattered around it. */
.item-cell.is-open > .item-inner.has-hero,
.spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero {
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr) minmax(0, 1fr);
  grid-template-areas:
    ".     title meta"
    "desc  hero  people";
  gap: clamp(1rem, 2vw, 2rem) clamp(1.25rem, 2.5vw, 2.5rem);
  align-items: center;
  width: min(1240px, calc(var(--stage, 1240px) * 0.94));
}

.item-inner.has-hero > .item-hero { grid-area: hero; align-self: center; }
.item-inner.has-hero > .item { grid-area: title; align-self: end; }
.item-cell.is-open > .item-inner.has-hero .index-detail { display: contents; }
.item-inner.has-hero .piece-meta { grid-area: meta; align-self: end; text-align: right; }
.item-inner.has-hero .piece-desc { grid-area: desc; align-self: start; }
.item-inner.has-hero .piece-people {
  grid-area: people;
  align-self: start;
  display: grid;
  gap: clamp(1rem, 2vw, 1.75rem);
}

.item-cell.is-open > .item-inner.has-hero > .item,
.item-inner.has-hero .piece {
  transform: translate(var(--nx, 0), var(--ny, 0)) rotate(var(--tilt, 0deg));
}

.item-inner.has-hero .piece-desc p,
.item-inner.has-hero .piece-creator p { margin: 0.4em 0 0; }
.item-inner.has-hero .piece-creator h3 { margin: 0.25em 0 0; }

.item-inner.has-hero .item-title {
  font-size: clamp(1.6rem, 3vw, 2.6rem);
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .item-cell.is-open > .item-inner.has-hero,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "meta" "title" "hero" "art" "desc" "people";
  }
  .item-inner.has-hero .piece-meta { text-align: left; }
}

.item-inner.has-hero > .item > .item-meta { display: none; }

/* Keep the scattered pieces inside the frame: room for their lean and drift,
   and never wider than the window. */
.item-cell.is-open > .item-inner.has-hero,
.spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero {
  max-width: calc(100vw - 32px);
  overflow-x: hidden;
  padding: 24px clamp(20px, 2.5vw, 32px);
}
.item-inner.has-hero .piece,
.item-cell.is-open .item-inner.has-hero .piece { min-width: 0; overflow-wrap: anywhere; }

/* Playing: the video widens across the profile and the notes around it dim. */
.item-cell.is-open > .item-inner.has-hero.is-playing,
.spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-playing {
  grid-template-areas:
    "hero   hero   hero"
    "art    title  meta"
    "desc   people people";
}
.item-inner.has-hero .piece,
.item-inner.has-hero > .item { transition: opacity 0.4s ease; }
.item-inner.is-playing .piece,
.item-inner.is-playing > .item { opacity: 0.6; }
.item-inner.is-playing { cursor: n-resize; }
.item-inner.is-playing a, .item-inner.is-playing .item-hero { cursor: auto; }

/* Titles break between words only, never mid-word. */
.item-title,
.item-cell.is-open .item-title,
.item-inner.is-long .item-title,
.item-inner.has-hero .item-title {
  overflow-wrap: normal;
  word-break: normal;
  hyphens: manual;
  text-wrap: balance;
}

/* While a video plays, the projects in the background fall further back. */
.spread.has-open:has(.item-inner.is-playing) .item-cell:not(.is-open) {
  opacity: 0.12;
  transition: opacity 0.5s ease;
}

/* Wordy profiles: the hero takes a bigger share of the width so it holds its
   own against the text, and stays centred beside it. Wide screens only; a
   phone keeps its single column. */
@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero.is-long:not(.is-playing),
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-long:not(.is-playing) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 2.6fr) minmax(0, 1fr);
  }
}
.item-inner.has-hero.is-long .index-detail { columns: auto; }

.item-cell.is-open .item-inner.has-hero > .item { text-align: left; }

/* The trinket as a playful overlay on the video's top-left corner. When the
   video plays it drops down beside the title. */
.item-companion {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  width: clamp(90px, 10vw, 160px);
  height: auto;
  max-height: 170px;
  object-fit: contain;
  transform: translate(-18%, 55%) rotate(-8deg);
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.45));
  pointer-events: none;
}
.item-inner.has-hero.is-playing > .item-companion {
  position: static;
  grid-area: art;
  justify-self: center;
  align-self: center;
  transform: rotate(-4deg);
  max-height: 120px;
}

/* The trinket hangs off a bottom corner, where there's always clear space;
   which corner is picked per project. */
.item-inner.has-hero[data-corner="right"]:not(.is-playing) .item-companion {
  left: auto;
  right: 0;
  transform: translate(18%, 55%) rotate(7deg);
}
.item-cell.is-open > .item-inner.has-hero:not(.is-playing),
.spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero:not(.is-playing) { padding-bottom: clamp(70px, 8vw, 120px); }

.item-inner.has-hero.long-title .item-title { font-size: clamp(1.25rem, 2vw, 1.8rem); }

/* The text columns centre on the video, whichever column is tallest. */
.item-inner.has-hero:not(.is-playing) .piece-desc,
.item-inner.has-hero:not(.is-playing) .piece-people { align-self: center; }
.item-inner.has-hero > .item-hero { overflow: visible; }
.item-still { position: relative; }
.item-still img { display: block; width: 100%; height: auto; object-fit: cover; }

/* The video frame's own image rules (full width and height) must not reach
   the trinket perched inside it. */
.item-hero img.item-companion {
  display: block;
  width: clamp(90px, 10vw, 160px);
  height: auto;
  max-height: 170px;
  object-fit: contain;
}

/* With a profile open, the background keeps only the project objects:
   no names, no titles, no text-only entries. */
.spread.has-open:not(.is-grid) .item-cell:not(.is-open):not(.has-art) { visibility: hidden; }
.spread.has-open:not(.is-grid) .item-cell:not(.is-open) .item-title,
.spread.has-open:not(.is-grid) .item-cell:not(.is-open) .item-name { visibility: hidden; }

/* The background objects recede: smaller and dimmer behind an open profile. */
.spread.has-open.is-river .item-cell:not(.is-open) { opacity: 0.35; }
.spread.has-open:not(.is-grid) .item-cell:not(.is-open) .item-art {
  scale: 0.65;
  transition: scale 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Breathing room between a creator's portrait, name and bio. */
.item-inner .piece-creator .detail-photo { margin-bottom: 1.1rem; }
.item-inner.has-hero .piece-creator h3 { margin: 0 0 0.6rem; }
.item-inner.has-hero .piece-creator h3 + p { margin-top: 0; }

/* Video mode: each creator becomes a side-by-side card, portrait on the left
   and name, bio and links beside it at a readable line length. */
.item-inner.is-playing .piece-desc,
.item-inner.is-playing .piece-people { align-self: start; }
.item-inner.is-playing .piece-creator {
  display: grid;
  grid-template-columns: clamp(110px, 12vw, 170px) minmax(0, 62ch);
  column-gap: clamp(1.25rem, 2.5vw, 2.25rem);
  align-items: start;
}
.item-inner.is-playing .piece-creator > * { grid-column: 2; }
.item-inner.is-playing .piece-creator > .detail-photo {
  grid-column: 1;
  grid-row: 1 / span 20;
  width: 100%;
  margin: 0;
}
.item-inner.is-playing .piece-creator h3 { margin-top: 0; }

/* The title owns the profile's top-left corner, spanning above the
   description and video; below it, the three columns share one top line. */
@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero:not(.is-playing),
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero:not(.is-playing) {
    grid-template-areas:
      "title title meta"
      "desc  hero  people";
    grid-template-rows: auto 1fr;
    align-items: start;
  }
  .item-inner.has-hero:not(.is-playing) > .item { align-self: end; justify-self: start; max-width: 100%; }
  .item-inner.has-hero:not(.is-playing) > .item-hero { align-self: start; }
  .item-inner.has-hero:not(.is-playing) .piece-desc,
  .item-inner.has-hero:not(.is-playing) .piece-people { align-self: start; }
  .item-inner.has-hero:not(.is-playing) .piece-meta { align-self: end; }
}

/* Video mode, framed: the video across the top, the title in the top-left
   corner beneath it, then the trinket and description on the left with the
   creator cards beside them. */
@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero.is-playing,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-playing {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      "hero  hero   hero"
      "title title  meta"
      "art   people people"
      "desc  people people";
    grid-template-rows: auto auto auto 1fr;
    align-items: start;
  }
  .item-inner.has-hero.is-playing > .item { align-self: end; justify-self: start; }
  .item-inner.has-hero.is-playing .piece-meta { align-self: end; }
  .item-inner.has-hero.is-playing > .item-companion { justify-self: start; align-self: start; }
  .item-inner.has-hero.is-playing .piece-people { align-self: start; }
}

/* Long descriptions and bios are cut to a manageable height with a fade.
   Hovering lets the text grow downward over the empty space below (up to
   --reach) without moving anything else; only text longer than that scrolls. */
@property --fade {
  syntax: '<length>';
  inherits: false;
  initial-value: 4.5em;
}
.item-inner.has-hero:not(.is-playing) .piece-desc { --clamp: 15.5em; --reach: 40em; }
.item-inner.has-hero:not(.is-playing) .piece-people { --clamp: 32em; --reach: 60em; }
.item-inner.has-hero:not(.is-playing) .piece-desc,
.item-inner.has-hero:not(.is-playing) .piece-people {
  max-height: var(--clamp);
}
.item-inner.has-hero:not(.is-playing) .is-clamped {
  height: var(--clamp);
  overflow: visible;
  position: relative;
  outline: none;
  cursor: s-resize;
}
.is-clamped > .clamp-body {
  --fade: 4.5em;
  position: absolute;
  inset: 0 0 auto;
  max-height: var(--clamp);
  padding-right: 0.9rem;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--fade)), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - var(--fade)), transparent);
  transition: max-height 0.9s cubic-bezier(0.22, 1, 0.36, 1), --fade 0.9s ease;
}
.item-inner.has-hero:not(.is-playing) .is-clamped:hover,
.item-inner.has-hero:not(.is-playing) .is-clamped:focus-within { z-index: 3; cursor: auto; }
.is-clamped:hover > .clamp-body,
.is-clamped:focus-within > .clamp-body {
  --fade: 0em;
  max-height: max(var(--clamp), min(var(--reach), var(--room, 999em)));
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--text-soft) transparent;
  transition: max-height 0.8s cubic-bezier(0.22, 1, 0.36, 1), --fade 0.7s ease;
}
.is-clamped:hover > .clamp-body.can-scroll,
.is-clamped:focus-within > .clamp-body.can-scroll { overflow-y: auto; }

/* With long text cut down, the description and creator column centre on the video again. */
@media (min-width: 761px) {
  .item-inner.has-hero:not(.is-playing) > .item-hero,
  .item-inner.has-hero:not(.is-playing) .piece-desc,
  .item-inner.has-hero:not(.is-playing) .piece-people { align-self: center; }
}

/* The profile frame still scrolls with the wheel, but never shows a bar. */
.item-cell.is-open > .item-inner { scrollbar-width: none; }
.item-cell.is-open > .item-inner::-webkit-scrollbar { display: none; }

/* While a video plays nothing is cut, so the text layer sits back in the flow. */
.item-inner.is-playing .clamp-body {
  position: static;
  max-height: none;
  padding-right: 0;
  overflow: visible;
  -webkit-mask-image: none;
  mask-image: none;
}
.item-inner.is-playing .is-clamped { cursor: auto; }

/* Inside a cut text layer, pieces keep still: their drift would push letters
   past the layer's edge, where they'd be clipped. */
.item-cell.is-open .item-inner .clamp-body .piece { transform: none; }
.clamp-body { padding-left: 2px; }

/* Paused or finished: the text below the video comes back to full strength. */
.item-inner.is-playing.is-paused .piece,
.item-inner.is-playing.is-paused > .item,
.item-inner.is-playing.is-paused > .item-companion { opacity: 1; }
.item-inner.is-playing.is-reading .piece,
.item-inner.is-playing.is-reading > .item,
.item-inner.is-playing.is-reading > .item-companion { opacity: 1; }

/* Other projects by the same person: small thumbnails under the hero. */
.item-also { display: none; }
.item-cell.is-open .item-also { display: block; grid-area: also; align-self: start; }
.item-also-group + .item-also-group { margin-top: clamp(1.6rem, 2.6vw, 2.2rem); }
.item-also-label {
  margin: 0 0 0.5rem;
  color: var(--text-soft);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.item-also-list { display: flex; flex-wrap: wrap; gap: 0.9rem 2rem; }
.item-also-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  max-width: 20rem;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}
.item-also-thumb {
  flex: none;
  width: 112px;
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: contain;
  transition: scale 0.25s ease;
}
.item-also-thumb.is-photo { object-fit: cover; }
.item-also-link span { border-bottom: 1px solid currentColor; }
.item-also-link:hover .item-also-thumb { scale: 1.08; }
.item-also-link:hover span { border-bottom-width: 2px; }

@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero:not(.is-playing),
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero:not(.is-playing) {
    grid-template-areas:
      "title title meta"
      "desc  hero  people"
      ".     also  people";
    grid-template-rows: auto auto 1fr;
  }
  .item-cell.is-open > .item-inner.has-hero.is-playing,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-playing {
    grid-template-areas:
      "hero  hero   hero"
      "title title  meta"
      "art   people people"
      "desc  people people"
      "also  people people";
    grid-template-rows: auto auto auto auto 1fr;
  }
}
@media (max-width: 760px) {
  .item-cell.is-open > .item-inner.has-hero,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero {
    grid-template-areas: "meta" "title" "hero" "also" "art" "desc" "people";
  }
}
.item-cell.is-open > .item-inner:not(.has-hero) .item-also { grid-column: 1 / -1; }

/* Text in a cut layer always wraps; nothing may slide sideways out of view. */
.clamp-body { overflow-x: hidden !important; overflow-wrap: anywhere; }

/* Leave room under the video for the trinket hanging off its corner. */
.item-inner.has-hero:not(.is-playing):has(.item-companion) .item-also {
  margin-top: clamp(84px, 9vw, 120px);
}

/* A quiet pill beside the title of work still in progress, on its profile only. */
.wip-pill {
  display: inline-block;
  margin-left: 0.9em;
  padding: 0.25em 0.7em 0.2em;
  border: 1px solid currentColor;
  border-radius: 999px;
  color: var(--text-soft);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: max(0.7rem, 0.32em);
  font-weight: 400;
  letter-spacing: 0.08em;
  line-height: 1;
  vertical-align: 0.45em;
  white-space: nowrap;
}
.item-cell:not(.is-open) .wip-pill { display: none; }
.index-title .wip-pill { opacity: 0.45; margin-left: 0.9em; font-size: 0.62rem; vertical-align: 0.1em; }

/* Show / hide work in progress: a label, then its own pill switch. */
.wip-filter {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.55rem;
  margin: 0.9rem 0 0.4rem;
  color: var(--text-soft);
  font-size: 0.85rem;
}
.wip-toggle {
  position: relative;
  flex: none;
  width: 1.75rem;
  height: 0.95rem;
  padding: 0;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: none;
  color: var(--text-soft);
  cursor: pointer;
  transition: color 0.3s ease, background 0.3s ease;
}
.wip-toggle::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0.15rem;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: currentColor;
  translate: 0 -50%;
  transition: translate 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}
.wip-toggle[aria-pressed='true'] { color: var(--index-ink); background: rgba(255, 255, 255, 0.12); }
.wip-toggle[aria-pressed='true']::after { translate: 0.8rem -50%; }
.wip-filter:has(.wip-toggle[aria-pressed='true']) { color: var(--index-ink); }
.wip-toggle:focus-visible { outline: 2px dashed var(--line); outline-offset: 4px; }

/* Category and genre tags, drawn like the WIP pill. */
.detail-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.item-inner.has-hero .piece-meta .detail-meta { justify-content: flex-end; }
.meta-pill {
  display: inline-block;
  padding: 0.3em 0.75em 0.25em;
  border: 1px solid currentColor;
  border-radius: 999px;
  color: var(--text-soft);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  line-height: 1.1;
  white-space: nowrap;
}

/* Related work titles read in the page's light text colour. */
.item-also-link { color: var(--text); }
.item-also-link:hover { color: #fff; }

/* Image-series variant (Archival Objects): a slideshow in the hero spot and a
   row of small cards beneath it. Only profiles carrying .has-cards / slides use this. */
.item-slides { position: relative; overflow: hidden; background: rgba(0, 0, 0, 0.25); }
.item-slides .slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.item-slides .slide.is-current { opacity: 1; }
.slide-arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  padding: 0;
  border: 1px solid rgba(244, 236, 216, 0.6);
  border-radius: 50%;
  background: rgba(10, 6, 20, 0.45);
  color: var(--text);
  translate: 0 -50%;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.25s ease, background 0.2s ease;
}
.slide-arrow svg { width: 1.1rem; fill: none; stroke: currentColor; stroke-width: 2; }
.slide-arrow.is-prev { left: 0.75rem; }
.slide-arrow.is-prev svg { scale: -1 1; }
.slide-arrow.is-next { right: 0.75rem; }
.item-slides:hover .slide-arrow,
.slide-arrow:focus-visible { opacity: 1; }
.slide-arrow:hover { background: rgba(10, 6, 20, 0.7); }
.slide-dots {
  position: absolute;
  left: 50%;
  bottom: 0.75rem;
  z-index: 2;
  display: flex;
  gap: 0.45rem;
  translate: -50% 0;
}
.slide-dot {
  width: 0.5rem;
  height: 0.5rem;
  padding: 0;
  border: 1px solid var(--text);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}
.slide-dot[aria-current='true'] { background: var(--text); }

.item-cards { display: none; }
.item-cell.is-open .item-cards {
  display: flex;
  grid-area: cards;
  gap: 0.6rem;
  overflow-x: auto;
  padding: 0.3rem 0.2rem 0.6rem;
  scrollbar-width: thin;
  scrollbar-color: var(--text-soft) transparent;
}
.item-card {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  transition: translate 0.2s ease;
}
.item-card img {
  display: block;
  height: clamp(84px, 9vw, 120px);
  width: auto;
  border-radius: 7px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
}
.item-card:hover { translate: 0 -4px; }

@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero.has-cards:not(.is-playing),
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.has-cards:not(.is-playing) {
    grid-template-areas:
      "title title meta"
      "desc  hero  people"
      ".     cards people"
      ".     also  people";
    grid-template-rows: auto auto auto 1fr;
  }
  .item-inner.has-cards:not(.is-playing) > .item-hero { align-self: center; }
}
@media (max-width: 760px) {
  .item-cell.is-open > .item-inner.has-hero.has-cards,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.has-cards {
    grid-template-areas: "meta" "title" "hero" "cards" "also" "desc" "people";
  }
}

/* A card opened large over the page. */
.card-view {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 0.8rem;
  padding: clamp(16px, 4vw, 56px);
  background: rgba(4, 3, 9, 0.88);
  opacity: 0;
  transition: opacity 0.25s ease;
}
.card-view.is-shown { opacity: 1; }
.card-view-image { max-width: min(90vw, 520px); max-height: calc(100dvh - 160px); object-fit: contain; border-radius: 22px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); }
.card-view-caption { margin: 0; color: var(--text-soft); font-family: 'DM Mono', ui-monospace, monospace; font-size: 0.85rem; }
.card-view-close {
  position: absolute;
  top: clamp(1rem, 2.5vw, 1.75rem);
  right: clamp(1rem, 3vw, 2.5rem);
  padding: 0.3rem 0;
  border: 0;
  border-bottom: 1px solid currentColor;
  background: none;
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  cursor: pointer;
}
.card-view .slide-arrow { opacity: 1; }
.card-view .slide-arrow.is-prev { left: clamp(1rem, 4vw, 3rem); }
.card-view .slide-arrow.is-next { right: clamp(1rem, 4vw, 3rem); }

/* Image-series variant opened up: the slideshow across the top, the card row
   straight beneath it, then the title and text. */
.item-inner:not(.is-playing) > .item-slides { cursor: zoom-in; }
@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero.has-cards.is-playing,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.has-cards.is-playing {
    grid-template-areas:
      "hero  hero   hero"
      "cards cards  cards"
      "title title  meta"
      "art   people people"
      "desc  people people"
      "also  people people";
    grid-template-rows: auto auto auto auto auto 1fr;
  }
}
.item-inner.has-cards.is-playing .item-card img { height: clamp(96px, 10vw, 140px); }
.item-inner.has-cards.is-playing .item-cards { opacity: 1; }

/* Per-project tweaks to the trinket on the hero's corner. */
.item-inner[data-slug="archival-objects"]:not(.is-playing) .item-hero img.item-companion {
  width: clamp(64px, 7vw, 110px);
  max-height: 120px;
  transform: translate(-22%, 45%) rotate(-16deg);
}
.item-inner[data-slug="archival-objects"][data-corner="right"]:not(.is-playing) .item-hero img.item-companion {
  transform: translate(22%, 45%) rotate(16deg);
}
/* The card row clears a trinket hanging off the hero's corner. */
.item-inner.has-cards:not(.is-playing):has(.item-companion) .item-cards { margin-top: clamp(40px, 5vw, 70px); }

/* Several videos: their thumbnails as a picker row, numbered. */
.item-video-pick { position: relative; cursor: pointer; }
.item-video-pick img { aspect-ratio: 16 / 9; object-fit: cover; border-radius: 4px; }
.item-video-number {
  position: absolute;
  left: 0.35rem;
  bottom: 0.35rem;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  background: rgba(10, 6, 20, 0.7);
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.7rem;
}
.item-video-pick.is-current img { outline: 2px solid var(--text); outline-offset: 2px; }

/* Live web pieces: the poster with a launch pill, opening in a new tab. */
.item-web { position: relative; display: block; cursor: zoom-in; }
.item-inner.is-playing .item-web { cursor: default; }
.web-launch { text-decoration: none; cursor: pointer; }
.web-launch {
  position: absolute;
  left: 50%;
  top: 50%;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 1rem;
  border: 1px solid var(--text);
  border-radius: 999px;
  background: rgba(10, 6, 20, 0.6);
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.85rem;
  translate: -50% -50%;
  transition: scale 0.2s ease, background 0.2s ease;
}
.web-launch svg { width: 1rem; fill: none; stroke: currentColor; stroke-width: 2; }
.item-web:hover .web-launch,
.item-web:focus-visible .web-launch { scale: 1.06; background: rgba(10, 6, 20, 0.8); }

/* Profiles without a hero get the same breathing room at the edges, so a
   leaning title is never clipped by the frame. */
.item-cell.is-open > .item-inner:not(.has-hero) {
  max-width: calc(100vw - 32px);
  padding: 24px clamp(20px, 2.5vw, 32px);
}

/* Team projects: the team's name and members above each member's own details. */
.team-members { margin: 0.25rem 0 0.4rem; color: var(--text-soft); font-size: 0.85rem; }

/* A web piece with no preview image: a dark card with its title. */
.web-blank {
  display: grid;
  place-items: start;
  aspect-ratio: 16 / 9;
  padding: 1.1rem 1.3rem;
  border: 1px solid rgba(244, 236, 216, 0.25);
  background:
    repeating-linear-gradient(to bottom, rgba(255, 255, 255, 0.025) 0 2px, transparent 2px 4px),
    radial-gradient(ellipse at 30% 20%, rgba(120, 90, 180, 0.35), transparent 60%),
    #0d0a16;
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: clamp(1rem, 2vw, 1.6rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The interactive version of a video project, as a pill under the tags. */
.web-side-link {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.6rem;
  padding: 0.4rem 0.85rem;
  border: 1px solid var(--text);
  border-radius: 999px;
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.8rem;
  text-decoration: none;
}
.web-side-link svg { width: 0.9rem; fill: none; stroke: currentColor; stroke-width: 2; }
.web-side-link:hover { background: rgba(244, 236, 216, 0.1); }

/* Several creators: the cut text layer wraps them, so it keeps the column's
   spacing between each person; in video mode each card gets more room. */
.item-inner.has-hero .clamp-body { display: grid; gap: clamp(1rem, 2vw, 1.75rem); align-content: start; }
.item-inner.is-playing .clamp-body,
.item-inner.is-playing .piece-people { gap: clamp(1.75rem, 3vw, 2.5rem); }
.item-inner.is-playing .piece-creator { min-height: clamp(110px, 12vw, 170px); }
.item-inner.is-playing .piece-team { padding-bottom: 0.5rem; border-bottom: 1px solid rgba(244, 236, 216, 0.15); }

/* An embedded web piece running inside the opened-up profile. */
.item-web.is-live { aspect-ratio: 16 / 9; }
.web-shield {
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: zoom-in;
}
.item-inner.is-playing .web-shield { display: none; }
.item-web.is-live .web-launch { z-index: 2; }
.web-live { display: block; width: 100%; height: 100%; border: 0; background: #000; }
.item-web.is-live .web-launch {
  position: absolute;
  top: auto;
  left: auto;
  right: 0.75rem;
  bottom: 0.75rem;
  translate: none;
  padding: 0.35rem 0.75rem;
  font-size: 0.75rem;
}

/* A web piece built for phones, playing inside a handset. */
.item-web.is-phone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  aspect-ratio: auto;
  background: none;
}
.phone {
  --ph: clamp(340px, 52vh, 520px);
  height: var(--ph);
  aspect-ratio: 375 / 812;
  padding: 10px;
  border-radius: 34px;
  background: #0b0b0d;
  box-shadow: 0 0 0 1px rgba(244, 236, 216, 0.12), 0 24px 60px rgba(0, 0, 0, 0.5);
  transition: height 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.item-inner.is-playing .phone { --ph: min(72vh, 680px); }
.phone-screen {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 25px;
  background: #000;
}
.phone-screen .web-live {
  position: absolute;
  top: 0;
  left: 0;
  width: 375px;
  height: 812px;
  transform-origin: top left;
}
.item-web.is-phone .web-launch,
.item-web.is-phone.is-live .web-launch {
  position: static;
  translate: none;
  padding: 0.3rem 0.7rem;
  font-size: 0.72rem;
}
.item-web.is-phone .web-shield { border-radius: 34px; }
.item-inner.has-hero:not(.is-playing) .piece-people:not(.is-clamped):has(.piece-creator + .piece-creator) { max-height: none; }

/* Several creators: each starts as a small portrait and name; hovering (or
   focusing) one grows the portrait and unrolls its bio, scrolling if long. */
.item-inner.many-creators:not(.is-playing) .piece-people { align-self: start; }
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 1.1rem;
  align-items: center;
  outline: none;
  cursor: default;
}
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team) > .detail-photo {
  grid-row: 1;
  width: 56px;
  height: 56px;
  margin: 0;
  object-fit: cover;
  transition: width 0.45s cubic-bezier(0.22, 1, 0.36, 1), height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team) > h3 { grid-column: 2; grid-row: 1; margin: 0; }
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team) > :not(.detail-photo):not(h3) {
  grid-column: 1 / -1;
  max-height: 0;
  margin: 0;
  overflow: hidden;
  opacity: 0;
  transition: max-height 0.5s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s ease, margin 0.35s ease;
}
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team):is(:hover, :focus-within) > .detail-photo {
  width: 120px;
  height: 120px;
}
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team):is(:hover, :focus-within) > p {
  max-height: 13em;
  margin-top: 1.2rem;
  padding-right: 0.8rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 1;
  scrollbar-width: thin;
  scrollbar-color: var(--text-soft) transparent;
}
.item-inner.many-creators:not(.is-playing) .piece-creator:not(.piece-team):is(:hover, :focus-within) > :not(.detail-photo):not(h3):not(p) {
  max-height: 12em;
  margin-top: 1.1rem;
  opacity: 1;
}

/* Compact creator list: steady spacing, and no drift that could close the gaps. */
.item-inner.many-creators:not(.is-playing) .piece-people { gap: clamp(1.4rem, 2.4vw, 2rem); }
.item-cell.is-open .item-inner.many-creators:not(.is-playing) .piece-people .piece-creator { transform: none; }

/* Team members with their roles. */
.team-roles { display: grid; gap: 0.45rem; margin: 0.5rem 0 0; padding: 0; list-style: none; }
.team-roles li { display: grid; gap: 0.05rem; }
.team-role-name { color: var(--text); font-size: 0.88rem; }
.team-role { color: var(--text-soft); font-size: 0.8rem; }
.item-inner.has-hero:not(.is-playing) .is-unclamped { max-height: none; }

/* Collapsible categories in the index. */
.index-heading { padding-bottom: 0; }
.index-toggle {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0 0 0.6rem;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.index-toggle > span:nth-child(2) { flex: 1; }
.index-caret {
  width: 0.45rem;
  height: 0.45rem;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  rotate: 45deg;
  translate: 0 -0.15rem;
  transition: rotate 0.36s cubic-bezier(0.22, 1, 0.36, 1), translate 0.36s cubic-bezier(0.22, 1, 0.36, 1);
}
.index-group.is-collapsed .index-caret { rotate: -45deg; translate: 0 0; }
.index-group .index-list { overflow: hidden; }
.index-group.is-collapsed:not(.is-folding) .index-list { display: none; }
.index-toggle:focus-visible { outline: 2px dashed var(--line); outline-offset: 4px; }

/* Several side links (documents, project pages) stack neatly under the tags. */
.piece-meta .web-side-link { margin-left: 0.4rem; }
.item-inner.has-hero .piece-meta { display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; }
.doc-link span { max-width: 18rem; overflow-wrap: anywhere; text-align: left; }
@media (max-width: 760px) { .item-inner.has-hero .piece-meta { align-items: flex-start; } }

/* Tabs switching between documents in the hero. */
.web-tabs {
  /* Sits just above the viewer, clear of the PDF's own toolbar. */
  position: absolute;
  bottom: calc(100% + 0.5rem);
  left: 0;
  z-index: 2;
  display: flex;
  gap: 0.35rem;
}
.web-tab {
  padding: 0.3rem 0.7rem;
  border: 1px solid rgba(244, 236, 216, 0.6);
  border-radius: 999px;
  background: rgba(10, 6, 20, 0.7);
  color: var(--text);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  cursor: pointer;
}
.web-tab[aria-pressed='true'] { background: var(--text); color: #140f1f; border-color: var(--text); }
.web-tab:focus-visible { outline: 2px dashed var(--line); outline-offset: 3px; }
/* Room above a tabbed viewer so its tabs are never clipped by the profile's edge. */
.item-web:has(.web-tabs) { margin-top: 2.6rem; }

/* Zooming in on an opened picture. */
.card-view-image {
  cursor: zoom-in;
  transition: scale 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}
.card-view.is-zoomed .card-view-image { scale: 2.4; cursor: zoom-out; }
.card-view.is-zoomed { overflow: hidden; }
.card-view.is-zoomed .slide-arrow,
.card-view.is-zoomed .card-view-caption { opacity: 0; pointer-events: none; }
/* Wide photos can open wider; tall cards are still held by the height limit. */
.card-view .card-view-image { max-width: min(90vw, 1100px); }

/* With a thumbnail row: the description, hero and creator column share one row,
   all centred on each other, so the text lines up with the viewer; the
   thumbnails and related work follow beneath the hero. */
@media (min-width: 761px) {
  .item-cell.is-open > .item-inner.has-hero.has-cards:not(.is-playing),
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.has-cards:not(.is-playing) {
    grid-template-areas:
      "title title meta"
      "desc  hero  people"
      ".     cards ."
      ".     also  .";
    grid-template-rows: auto auto auto 1fr;
  }
  .item-inner.has-cards:not(.is-playing) > .item-hero,
  .item-inner.has-cards:not(.is-playing) .piece-desc,
  .item-inner.has-cards:not(.is-playing) .piece-people { align-self: center; }
  .item-inner.has-cards:not(.is-playing) .item-also { align-self: start; }
}

/* Breathing room above a tall profile: it starts lower and is a touch shorter. */
.item-cell.is-open > .item-inner { max-height: calc(100dvh - 88px); }
/* With a thumbnail row the related work needn't leave room for a trinket. */
.item-inner.has-cards:not(.is-playing) .item-also,
.item-inner.has-hero.has-cards:not(.is-playing):has(.item-companion) .item-also { margin-top: 1.6rem; }

/* Background objects light up while the visitor scrolls them, then dim again. */
.spread.has-open.is-river-live .item-cell:not(.is-open) { transition: opacity 0.6s ease; }
.spread.has-open.is-river.is-scrolling .item-cell:not(.is-open),
.spread.has-open.is-river.is-scrolling:has(.item-inner.is-playing) .item-cell:not(.is-open) {
  opacity: 0.9;
  transition: opacity 0.25s ease;
}
.spread.has-open.is-river.is-scrolling .item-cell:not(.is-open) .item-art { scale: 0.8; }

/* Hovering a background object behind a profile lights it up and shows a small
   tag with its project's name. */
.spread.has-open.is-river .item-cell:not(.is-open).has-art:hover,
.spread.has-open.is-river:has(.item-inner.is-playing) .item-cell:not(.is-open).has-art:hover {
  z-index: 6;
  opacity: 1;
  transition: opacity 0.2s ease;
}
.spread.has-open.is-river .item-cell:not(.is-open).has-art:hover .item-art { scale: 0.85; }
/* The object's name, following the cursor while it's over the object. */
.cursor-tag {
  position: fixed;
  z-index: 30;
  left: 0;
  top: 0;
  max-width: 14rem;
  color: #f4ecd8;
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  line-height: 1.3;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
}
/* A black highlighter band behind the words, wrapping line by line. */
.cursor-tag span {
  padding: 0.1em 0.35em;
  background: #000;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
.cursor-tag.is-shown { opacity: 1; }

/* The student's object can be clicked in an open profile, and once picked up it
   is the cursor everywhere in that profile, video mode included. */
.item-cell.is-open .item-art,
.item-cell.is-open .item-companion { pointer-events: auto; cursor: grab; }
.item-inner.has-object-cursor,
.item-inner.has-object-cursor * { cursor: none !important; }
.item-inner.has-object-cursor iframe { cursor: auto !important; }
/* The carried object: hung from its top centre, just below the pointer. */
.object-cursor {
  position: fixed;
  z-index: 60;
  left: 0;
  top: 0;
  height: auto;
  margin-top: -4px;
  transform-origin: 50% 0;
  pointer-events: none;
  opacity: 0;
  filter: drop-shadow(0 8px 10px rgba(0, 0, 0, 0.45));
  transition: opacity 0.15s ease;
}
.object-cursor.is-shown { opacity: 1; }

/* The object's spot while it's being carried: empty, but still clickable, so a
   click there puts it back. */
.item-cell.is-open .item-art { transition: opacity 0.3s ease, scale 0.35s cubic-bezier(0.22, 1.4, 0.36, 1); }
/* What's left behind: a dashed line round the object's silhouette, so the empty
   spot still shows what belongs there. */
.item-cell.is-open .item-art.is-carried {
  object-position: -200vw 0;
  background: var(--art-outline) center / contain no-repeat;
  filter: none;
  opacity: 0.75;
  animation: ghost-in 0.4s ease;
}
@keyframes ghost-in {
  from { opacity: 0; scale: 0.92; }
}

/* The Cabinet of Curiosities logo fills the space above an open profile; with a
   video or other piece opened up it shrinks and fades back. */
.profile-logo {
  position: fixed;
  z-index: 3;
  top: clamp(1rem, 4vh, 2.5rem);
  left: calc(var(--index-width) + (100vw - var(--index-width)) / 2);
  width: auto;
  height: clamp(56px, 13vh, 130px);
  translate: -50% 0;
  filter: brightness(0) invert(0.93) sepia(0.18);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease, scale 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: 50% 0;
}
body:has(.spread.has-open:not(.is-grid)) .profile-logo { opacity: 0.85; }
body:has(.item-inner.is-playing) .profile-logo { opacity: 0.25; scale: 0.6; }
/* Phones: the logo stays at the top of the trinket list, between the menu and
   the cabinet link, but steps aside for an open profile. */
@media (max-width: 760px) {
  .profile-logo {
    position: absolute;
    top: 4.25rem;
    left: 50%;
    height: clamp(56px, 11vh, 90px);
  }
  /* With a profile open it stays pinned at the top, small, and the profile
     is laid out below it. */
  body:has(.spread.has-open) .profile-logo {
    position: fixed;
    /* Below the row holding the menu and the back link, so it never sits on them. */
    top: 3.6rem;
    height: clamp(40px, 7vh, 56px);
    opacity: 0.85;
  }
  body:has(.item-inner.is-playing) .profile-logo { opacity: 0.85; scale: 1; }
}

/* A single thumbnail (such as one poster) sits centred under the hero. */
.item-cell.is-open .item-cards:has(> .item-card:only-child) { justify-content: center; }

/* A phone piece with a video: the video's thumbnail tucked behind the phone's
   left edge, still clickable; opened up, the two stand side by side. */
.item-web.is-phone.has-side-video { flex-direction: row; justify-content: center; align-items: center; }
.phone-side {
  position: relative;
  z-index: 0;
  flex: none;
  width: clamp(200px, 22vw, 340px);
  aspect-ratio: 16 / 9;
  margin-right: calc(clamp(200px, 22vw, 340px) * -0.18);
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 8px;
  background: #000;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
  cursor: pointer;
  transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1), margin 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.phone-side img,
.phone-side iframe { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }
.phone-side svg {
  position: absolute;
  top: 50%;
  left: 40%;
  width: 52px;
  translate: -50% -50%;
}
.phone-side svg circle { fill: rgba(10, 6, 20, 0.55); stroke: var(--text); stroke-width: 2; }
.phone-side svg path { fill: var(--text); }
.item-web.has-side-video .phone { position: relative; z-index: 1; }
.item-web.is-phone .phone { position: relative; }
/* Opened up: side by side, the video larger and no longer tucked behind. */
.item-inner.is-playing .phone-side {
  /* Takes whatever width the phone leaves, so the pair always fits the frame. */
  flex: 1 1 0;
  width: auto;
  min-width: 0;
  max-height: var(--ph);
  margin-right: clamp(1rem, 2.5vw, 2rem);
}
.item-inner.is-playing .phone { flex: none; }
.item-inner.is-playing .item-web.has-side-video { width: 100%; }
.item-inner.is-playing .phone-side svg { left: 50%; }

/* A small hand-written nudge on live embedded pieces, gone once opened up.
   It sits just above the frame's top-right corner, its arrow curling down to
   land inside the frame. */
.interact-nudge {
  position: absolute;
  z-index: 3;
  right: 0.8rem;
  bottom: calc(100% + 0.3rem);
  display: flex;
  align-items: flex-start;
  gap: 0.2rem;
  color: #f4ecd8;
  font-family: 'Pixelify Sans', ui-monospace, monospace;
  font-size: 0.85rem;
  white-space: nowrap;
  rotate: -3deg;
  transform-origin: 100% 100%;
  pointer-events: none;
  animation: nudge-bob 2.4s ease-in-out infinite alternate;
  transition: opacity 0.3s ease;
}
.interact-nudge span { padding: 0.12em 0.4em; background: #000; }
.interact-nudge svg {
  flex: none;
  width: 1.9rem;
  height: 1.6rem;
  margin-top: 0.5rem;
  margin-bottom: -1.1rem;
  fill: none;
  stroke: #f4ecd8;
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* On the phone it sits off to the left, its arrow curling into the handset's
   top-left corner. */
.phone > .interact-nudge { right: calc(100% - 1.8rem); }
.item-inner.is-playing .interact-nudge { opacity: 0; }
@keyframes nudge-bob { to { translate: 0 -3px; } }

/* Object size: a slim vertical slider on the right, in Free flow only. */
.scale-control {
  position: fixed;
  z-index: 6;
  right: clamp(0.8rem, 1.8vw, 1.6rem);
  top: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  translate: 0 -50%;
  color: var(--text-soft);
  transition: opacity 0.3s ease;
}
.scale-control input {
  writing-mode: vertical-lr;
  direction: rtl;
  width: 4px;
  height: clamp(120px, 22vh, 200px);
  margin: 0;
  appearance: none;
  background: rgba(244, 236, 216, 0.25);
  border-radius: 999px;
  cursor: pointer;
}
.scale-control input::-webkit-slider-thumb {
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #f4ecd8;
}
.scale-control input::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: #f4ecd8;
}
.scale-control input:focus-visible { outline: 2px dashed var(--line); outline-offset: 6px; }
.scale-icon { width: 7px; height: 7px; border: 1.5px solid currentColor; border-radius: 2px; }
.scale-icon-big { width: 12px; height: 12px; }
body:has(.spread.has-open) .scale-control { opacity: 0; pointer-events: none; }
/* In Grid only the view button stays; sizing and shuffling belong to Free flow. */
body:has(.spread.is-grid) .scale-slider,
body:has(.spread.is-grid) .shuffle-button { display: none; }
/* Phones keep just the view button; the slider and shuffle need room. */
@media (max-width: 760px) { .scale-slider { display: none; } }
.spread.is-scaling .item-cell { transition: left 0.35s ease-out, top 0.35s ease-out, width 0.35s ease-out; }

/* The logo also crowns the top of Free flow, with clear space beneath it, and
   fades once the page is scrolled. */
body:has(.spread:not(.is-grid)) .profile-logo { opacity: 0.85; }
body.is-scrolled:has(.spread:not(.is-grid):not(.has-open)) .profile-logo { opacity: 0; }
body:has(.item-inner.is-playing) .profile-logo { opacity: 0.25; scale: 0.6; }

/* The shuffle button above the size slider. */
.scale-slider { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; }
.shuffle-button {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  margin-bottom: 0.6rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-soft);
  cursor: pointer;
  transition: color 0.2s ease, rotate 0.4s ease;
}
.shuffle-button svg { width: 1.15rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.shuffle-button:hover { color: #f4ecd8; }
.shuffle-button:active { rotate: 180deg; }
.shuffle-button:focus-visible { outline: 2px dashed var(--line); outline-offset: 4px; }
.spread.is-shuffling .item-cell { transition: left 1.1s cubic-bezier(0.22, 1, 0.36, 1), top 1.1s cubic-bezier(0.22, 1, 0.36, 1), width 1.1s cubic-bezier(0.22, 1, 0.36, 1); }

/* The view button at the top of the right-hand controls: a grid icon in Free
   flow, a scatter icon in Grid, showing where it will take you. */
.view-toggle {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  margin-bottom: 0.2rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-soft);
  cursor: pointer;
  transition: color 0.2s ease;
}
.view-toggle svg { width: 1.15rem; fill: none; stroke: currentColor; stroke-width: 1.7; }
.view-toggle .icon-free { display: none; }
.view-toggle.is-grid .icon-grid { display: none; }
.view-toggle.is-grid .icon-free { display: block; }
.view-toggle:hover { color: #f4ecd8; }
.view-toggle:focus-visible { outline: 2px dashed var(--line); outline-offset: 4px; }

/* Collected objects: an inventory cut into the corner of the object area. */
.inventory {
  position: fixed;
  z-index: 6;
  right: clamp(0.8rem, 1.8vw, 1.6rem);
  bottom: clamp(0.8rem, 1.8vw, 1.6rem);
  width: min(300px, calc(100vw - 1.6rem));
  padding: 0.8rem;
  border: 1px dashed var(--index-ink);
  border-radius: 14px;
  background: rgba(10, 7, 18, 0.72);
  backdrop-filter: blur(6px);
  container-type: inline-size;
  color: var(--index-ink);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.85rem;
}
.inventory-bar { display: flex; align-items: baseline; gap: 0.8rem; }
.inventory-clear {
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-soft);
  font: inherit;
  font-size: 0.75rem;
  opacity: 0.6;
  cursor: pointer;
  transition: opacity 0.2s ease;
}
.inventory-clear:hover,
.inventory-clear:focus-visible { opacity: 1; text-decoration: underline; text-underline-offset: 3px; }
.inventory-head {
  flex: 1;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.inventory-head::after { content: ' \2212'; float: right; }
.inventory.is-folded .inventory-head::after { content: ' +'; }
.inventory-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: calc((100cqw - 0.3rem - 0.8rem) / 3);
  gap: 0.4rem;
  height: calc((100cqw - 0.3rem - 0.8rem) / 3 * 2 + 0.4rem);
  padding-right: 0.3rem;
  scrollbar-width: thin;
  scrollbar-color: var(--text-soft) transparent;
  margin-top: 0.7rem;
  overflow-y: auto;
}
.inventory.is-folded .inventory-grid { display: none; }
.inventory-slot {
  aspect-ratio: 1;
  padding: 0.3rem;
  border: 1px solid rgba(244, 236, 216, 0.25);
  border-radius: 10px;
  background: rgba(244, 236, 216, 0.05);
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.inventory-slot.is-empty { cursor: default; border-style: dashed; background: none; }
.inventory-slot:not(.is-empty):hover { background: rgba(244, 236, 216, 0.15); transform: translateY(-2px); }
.inventory-slot img { width: 100%; height: 100%; object-fit: contain; }
body:has(.spread.has-open) .inventory { opacity: 0; pointer-events: none; }
.inventory > .inventory-clear { display: block; margin: 0.6rem auto 0; }
.inventory.is-folded > .inventory-clear { display: none; }

@media (max-width: 760px) {
  .inventory {
    right: 0.75rem;
    bottom: 0.75rem;
    width: 190px;
    padding: 0.55rem;
    border-radius: 10px;
    font-size: 0.72rem;
  }
  .inventory-grid { gap: 0.3rem; margin-top: 0.45rem; }
  .inventory-slot { padding: 0.2rem; border-radius: 7px; }
  .inventory > .inventory-clear { margin-top: 0.4rem; font-size: 0.68rem; }
}

/* Rearranging the inventory by dragging. */
.inventory-slot:not(.is-empty) { touch-action: none; cursor: grab; }
.inventory-slot img { pointer-events: none; -webkit-user-drag: none; }
.inventory-grid.is-sorting, .inventory-grid.is-sorting .inventory-slot { cursor: grabbing; }
.inventory-slot.is-dragging {
  border-style: dashed;
  border-color: var(--index-ink);
  background: rgba(244, 236, 216, 0.18);
  transform: scale(1.06);
}

/* A background trinket drifting under the back link steps aside. */
.spread.has-open .item-cell.is-under-link { pointer-events: none; }
.spread.has-open .item-cell.is-under-link > .item { opacity: 0.15; transition: opacity 0.3s ease; }

/* A small heading over each student's links, so visitors know how to reach them. */
.detail-contact {
  margin: 1rem 0 0.35rem;
  color: var(--text-soft);
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.detail-contact + .detail-links { margin-top: 0; }

/* Theatre mode: a quiet spinner while the video player loads. */
.item-hero.is-loading { position: relative; background: #07050c; }
.item-hero.is-loading iframe { opacity: 0; }
.item-hero iframe { transition: opacity 0.4s ease; }
.item-hero.is-loading::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 2px solid rgba(244, 236, 216, 0.18);
  border-top-color: #f4ecd8;
  border-radius: 50%;
  animation: video-spin 0.9s linear infinite;
}
@keyframes video-spin { to { rotate: 360deg; } }

/* Phones: in theatre mode the video runs from one edge of the screen to the
   other, while the text below keeps its margins. */
@media (max-width: 760px) {
  .item-cell.is-open > .item-inner.has-hero.is-playing,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-playing {
    left: 0 !important;
    width: 100vw;
    max-width: 100vw;
    padding-left: 20px !important;
    padding-right: 20px !important;
  }
  /* The text keeps the 20px padding; only the video reaches out past it. */
  .item-inner.has-hero.is-playing > .item-hero {
    width: calc(100% + 40px);
    margin-left: -20px;
    margin-right: -20px;
    border-radius: 0;
    box-shadow: none;
  }
}

/* Phones: theatre mode keeps the logo fully visible above the video (this
   comes last so it wins over the shrink-and-fade used on larger screens). */
@media (max-width: 760px) {
  body:has(.item-inner.is-playing) .profile-logo { opacity: 0.85; scale: 1; }
  body.is-scrolled:has(.spread.has-open) .profile-logo { opacity: 0.85; }
}

/* Phones, theatre mode: one clear column under the video. The trinket shrinks
   and sits beside the title, the tags go below them, then the description
   and the creators, each with room to breathe. */
@media (max-width: 760px) {
  .item-cell.is-open > .item-inner.has-hero.is-playing,
  .spread:not(.is-grid) .item-cell.is-open > .item-inner.has-hero.is-playing {
    grid-template-columns: 64px minmax(0, 1fr);
    grid-template-rows: none;
    grid-template-areas:
      "hero   hero"
      "cards  cards"
      "art    title"
      "meta   meta"
      "desc   desc"
      "also   also"
      "people people";
    row-gap: 1.25rem;
    column-gap: 0.9rem;
    padding-bottom: 2rem;
  }
  .item-inner.has-hero.is-playing > .item { align-self: center; justify-self: start; }
  .item-inner.has-hero.is-playing .item-title { font-size: 1.35rem; line-height: 1.15; }
  .item-inner.has-hero.is-playing > .item-companion {
    justify-self: start;
    align-self: center;
    width: 64px;
    max-height: 64px;
    transform: none;
  }
  .item-inner.has-hero.is-playing .piece-meta { text-align: left; justify-self: start; }
  .item-inner.has-hero.is-playing .piece,
  .item-inner.has-hero.is-playing > .item { opacity: 0.85; }
  /* Creator cards: a small portrait beside the name, the bio full width below. */
  .item-inner.is-playing .piece-creator {
    grid-template-columns: 56px minmax(0, 1fr);
    column-gap: 0.8rem;
    row-gap: 0.4rem;
  }
  .item-inner.is-playing .piece-creator > * { grid-column: 1 / -1; }
  .item-inner.is-playing .piece-creator > .detail-photo {
    grid-column: 1;
    grid-row: 1;
    width: 56px;
    border-radius: 8px;
  }
  .item-inner.is-playing .piece-creator > .detail-photo + h3 { grid-column: 2; grid-row: 1; align-self: center; }
  .item-inner.is-playing .piece-people { display: grid; gap: 1.5rem; }
}

/* Phones: long text is never cut or revealed on hover; it simply sits in the
   page and the profile scrolls. */
@media (max-width: 760px) {
  .item-cell.is-open .piece-desc,
  .item-cell.is-open .piece-people { max-height: none; overflow: visible; }
  .item-cell.is-open .clamp-body {
    position: static;
    max-height: none;
    padding-right: 0;
    overflow: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* Phones: with a profile open the logo is a way back to the trinkets. */
@media (max-width: 760px) {
  body:has(.spread.has-open) .profile-logo { pointer-events: auto; cursor: pointer; }
}

/* Phones: while the project list is open it covers the top of the page, so the
   logo steps aside until it's closed again. */
@media (max-width: 800px) {
  body:has(.index:not(.is-collapsed)) .profile-logo { opacity: 0 !important; pointer-events: none !important; }
}

/* Phones: a bigger and a smaller button in place of the size slider. */
.scale-steps { display: none; }
@media (max-width: 760px) {
  .scale-steps { display: flex; flex-direction: column; gap: 0.4rem; }
  .scale-step {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid rgba(244, 236, 216, 0.35);
    border-radius: 50%;
    background: rgba(10, 7, 18, 0.55);
    color: var(--text);
    cursor: pointer;
  }
  .scale-step:disabled { opacity: 0.3; cursor: default; }
}

/* On wider screens the wrappers round the list step out of the way, so the
   sidebar lays out exactly as before. */
@media (min-width: 801px) {
  .index-body, .index-body-inner { display: contents; }
}

/* Phones: a faint rule under the open list, separating it from the trinkets. */
@media (max-width: 800px) {
  .index::after {
    content: '';
    position: absolute;
    left: 1.25rem;
    right: 1.25rem;
    bottom: 0;
    height: 1px;
    background: var(--index-ink);
    opacity: 0.3;
    transition: opacity 0.35s ease;
  }
  .index.is-collapsed::after { opacity: 0; }
  .index:not(.is-collapsed) { padding-bottom: 1rem; }
}

/* Phones: a phone piece with a video stacks them, the video across the top and
   the phone below it, rather than squeezing them side by side. */
@media (max-width: 760px) {
  .item-web.is-phone.has-side-video,
  .item-inner.is-playing .item-web.has-side-video {
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
  }
  .item-web.is-phone.has-side-video .phone-side,
  .item-inner.is-playing .phone-side {
    flex: none;
    width: 100%;
    max-height: none;
    margin: 0;
  }
  .item-inner.is-playing .phone-side { border-radius: 0; }
  .item-inner.is-playing .phone-side svg,
  .item-web.is-phone.has-side-video .phone-side svg { left: 50%; }
  .item-inner.is-playing .item-web.has-side-video .phone { --ph: min(70vh, 600px); }
}

/* Phones: behind a profile, a sparse scatter of small, dim objects as flavour
   only; they can't be tapped, and the rest step out entirely. */
.spread.is-flavour .item-cell:not(.is-open) {
  opacity: 0.18 !important;
  pointer-events: none;
  animation: none;
  transition: opacity 0.5s ease;
}
.spread.is-flavour .item-cell:not(.is-open) > .item { animation: none; }
.spread.is-flavour .item-cell.is-flavour-off { opacity: 0 !important; visibility: hidden; }

/* The next student, waiting at the very end of a profile (phones only). */
.profile-next { display: none; }
@media (max-width: 760px) {
  .item-cell.is-open .profile-next {
    grid-column: 1 / -1;
    display: grid;
    gap: 0.25rem;
    width: 100%;
    margin: 1.5rem 0 0.5rem;
    padding: 1rem 0 0;
    border: 0;
    border-top: 1px solid rgba(244, 236, 216, 0.25);
    background: none;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
    opacity: 1 !important;
  }
  .profile-next-label {
    color: var(--text-soft);
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .profile-next-title { font-family: 'Pixelify Sans', ui-monospace, monospace; font-size: 1.15rem; line-height: 1.2; }
}

/* Phones: no slider at all, only the larger and smaller buttons. (This sits at
   the end so it wins over the slider's own layout rule above.) */
@media (max-width: 760px) {
  .scale-control .scale-slider { display: none; }
}

/* Inventory slots: each trinket stays inside its own square, never larger than
   the empty slots beside it. */
.inventory-grid {
  grid-template-rows: repeat(2, minmax(0, 1fr));
  grid-auto-rows: minmax(0, calc((100cqw - 0.3rem - 0.8rem) / 3));
}
.inventory-slot {
  aspect-ratio: auto;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  box-sizing: border-box;
}
.inventory-slot img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* Phones: category and genre tags always fit. They line up from the left, wrap
   onto new rows, and a tag too long for the width wraps inside its own pill
   instead of being cut off at the edge. */
@media (max-width: 760px) {
  .item-cell.is-open .piece-meta {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    justify-self: stretch;
    text-align: left;
    transform: none !important;
    translate: none;
    rotate: none;
  }
  .item-cell.is-open .piece-meta .detail-meta,
  .item-inner.has-hero .piece-meta .detail-meta {
    justify-content: flex-start;
    max-width: 100%;
    min-width: 0;
  }
  .item-cell.is-open .meta-pill {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
    text-align: left;
    line-height: 1.25;
  }
}

/* Phones: a profile's own scrolling never carries on into the page behind. */
@media (max-width: 760px) {
  .item-cell.is-open > .item-inner { overscroll-behavior: contain; }
  html.river-lock, html.river-lock body { overflow: hidden; overscroll-behavior: none; }
}

/* Phones: profile text gets room to breathe, with looser lines and a clear gap
   between paragraphs. */
@media (max-width: 760px) {
  .item-cell.is-open .piece-desc p,
  .item-cell.is-open .piece-creator > p,
  .item-cell.is-open .clamp-body p {
    margin: 0;
    line-height: 1.7;
  }
  .item-cell.is-open .piece-desc p + p,
  .item-cell.is-open .piece-creator > p + p,
  .item-cell.is-open .clamp-body p + p { margin-top: 1.1em; }
  .item-cell.is-open .piece-creator h3 + p { margin-top: 0.5em; }
}

/* Phones: no size controls at all; trinkets stay at their default size. */
@media (max-width: 760px) {
  .scale-control .scale-steps,
  .scale-control .scale-slider { display: none !important; }
}

/* Phones: while the project list is open over a profile, the profile steps
   aside (fades out of the way) and returns when the list closes. */
@media (max-width: 800px) {
  .item-cell.is-open > .item-inner { transition: opacity 0.35s ease; }
  body:has(.index:not(.is-collapsed)) .item-cell.is-open > .item-inner {
    opacity: 0;
    pointer-events: none;
  }
  .index { z-index: 7; }
}

/* Phones, regular profile view: no Close button; the "← Back" link in the
   corner does the same job. (In theatre mode it stays, as "Back" out of the
   video.) */
@media (max-width: 760px) {
  .item-inner:not(.is-playing) .detail-close { display: none; }
}

/* The corner link (Back / Cabinet) always sits above everything at the top of
   the page, including the phone project list, so it can always be pressed. */
.page-link { z-index: 12; }

/* Phones: the shuffle button sits level with the logo at the top of the page,
   on the right, instead of halfway down the screen. Its centre matches the
   logo's: the logo starts 4.25rem down and is clamp(56px, 11vh, 90px) tall. */
@media (max-width: 760px) {
  .scale-control {
    top: calc(4.25rem + clamp(28px, 5.5vh, 45px));
    right: 1.25rem;
  }
  .scale-control .shuffle-button { margin-bottom: 0; }
}

/* Documents offered as buttons rather than embedded: stacked in the card's centre. */
.web-launches {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 1rem;
  pointer-events: none;
}
.web-launches .web-launch {
  position: static;
  translate: none;
  max-width: 100%;
  pointer-events: auto;
  white-space: normal;
  text-align: center;
}

/* Touch screens: a trinket in an open profile can be pressed and dragged to
   carry it, so a drag on it moves the trinket rather than scrolling. */
@media (pointer: coarse) {
  .item-cell.is-open .item-art { touch-action: none; }
}

/* Phones: no work-in-progress switch; every project always shows. */
@media (max-width: 800px) {
  .wip-filter { display: none; }
}

/* iPhones zoom the page in on any text box set smaller than 16px when it's
   tapped; the search box is kept at 16px on touch screens so that never happens. */
@media (pointer: coarse), (max-width: 800px) {
  .index-search input { font-size: 16px; }
}
