:root {
  --ink: #000;
  --ink-70: rgba(0, 0, 0, 0.7);
  --ink-40: rgba(0, 0, 0, 0.4);
  --bg: #fafafa;
  --font-sans: 'Lunchtype22', 'Helvetica Neue', Arial, sans-serif;
  --font-display: 'Bodoni Moda SC', 'Times New Roman', serif;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
}

img {
  display: block;
  max-width: 100%;
}

/* Identical to the homepage nav (and case-study.html's copy of it) — same
   markup, same rules, just fixed here since this page real-scrolls. */
/* Bottom-left, 24px in from both edges, where the homepage has it. */
.nav {
  position: fixed;
  left: 24px;
  bottom: 24px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-sans);
  font-weight: 800;
  text-transform: lowercase;
  z-index: 50;
}

.nav-link {
  position: relative;
  display: inline-block;
  color: var(--ink-70);
  text-decoration: none;
  font-size: 18px;
  line-height: 1;
  opacity: 0.4;
  transition: opacity 0.2s ease;
}

@media (hover: hover) and (pointer: fine) {
  .nav-link:hover {
    opacity: 0.7;
  }
}

.nav-link.active {
  font-size: 20px;
  line-height: 0.9;
  opacity: 1;
}

.nav-link::before {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  color: inherit;
  filter: blur(2px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  mask-image: linear-gradient(to bottom, black 0%, black 10%, transparent 10%);
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 10%, transparent 10%);
}

.nav-link.active::before {
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
  .nav-link:hover::before {
    opacity: 1;
  }
}

.nav-link .txt {
  position: relative;
  display: inline-block;
}

/* Left rail: fixed for the whole page (per the Figma frame, this column
   never leaves the viewport — the grid on the right is what scrolls),
   matching the homepage's own left-column positions (24px from the edge)
   at each element's Figma y-coordinate. */
.play-side {
  position: fixed;
  left: 24px;
  top: 0;
  width: 207px;
  height: 100vh;
  pointer-events: none;
  z-index: 10;
}

.play-side > * {
  pointer-events: auto;
}

/* Hidden until an image is hovered (see play.js toggling .is-visible) —
   there's nothing to show before then since these mirror whichever
   tile the cursor is over. */
.play-index {
  position: absolute;
  top: 336px;
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 39px;
  line-height: 0.994;
  color: var(--ink);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.play-bio {
  position: absolute;
  top: 388px;
  margin: 0;
  width: 207px;
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 12px;
  line-height: 1.333;
  color: var(--ink-70);
  opacity: 0;
  transition: opacity 0.2s ease;
}

.play-index.is-visible,
.play-bio.is-visible {
  opacity: 1;
}

/* Caption swaps (play.js): words need to be inline-block to move; spaces
   between them stay as text, so wrapping is unchanged. */
.swap-word {
  display: inline-block;
  white-space: nowrap;
}

.profile {
  position: absolute;
  top: 765px;
  left: 0;
  display: flex;
  align-items: center;
  gap: 13px;
}

.profile-photo {
  width: 44px;
  height: 48.889px;
  overflow: hidden;
  border-radius: 2px;
  flex-shrink: 0;
}

.profile-photo img {
  width: 100%;
  height: 120%;
  object-fit: cover;
}

.profile-name {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 21px;
  line-height: 1.13;
  color: var(--ink);
  white-space: nowrap;
}

/* Right column: a masonry-style photo grid via CSS multi-column, since
   the source images all share close to the same aspect ratio (~4:5) but
   the Figma layout staggers them per-column rather than in strict rows —
   multi-column is the simplest reliable way to get that staggered rhythm
   without hand-placing every tile. Spacing values (column gap, item
   margin, top/right padding) are taken directly from the Figma frame's
   own coordinates: grid frame at (374, 45) inside the 1440-wide canvas,
   150×184 tiles spaced ~271.7px apart on-center (a 122px gap) and
   stacked with an ~87px gap within each column. */
.play-grid {
  margin-left: 374px;
  padding: 45px 48px 128px 0;
}

/* Categories (Products & Experiments, Art & Illustration, ...): each its
   own block, well apart from the next. Its name sits just left of the
   pictures, in the gap between the hover rail and the grid (32px clear of
   the images, right-aligned), and stays pinned (sticky) while its
   category is on screen. The name and the tiles share one grid cell, so
   the name takes no room in the column; it is pulled left into the gap. */
.play-cat {
  display: grid;
}

.play-cat + .play-cat {
  margin-top: 200px;
}

.play-cat > * {
  grid-area: 1 / 1;
}

.play-cat-title {
  position: sticky;
  top: 24px;
  z-index: 5;
  align-self: start;
  justify-self: start;
  width: 104px;
  margin: 0 0 0 -136px;   /* its right edge 32px short of the pictures, its left clear of the hover rail */
  text-align: right;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.35;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.4);
}

.play-cat-items {
  column-count: var(--play-cols, 2);
  column-gap: 20px;
}

/* With play.js running, the tiles are dealt into one stack per column in
   reading order (01, 02, 03 across the top, then 04, 05, 06...), each tile
   keeping its own height; the CSS columns above are only the fallback. */
.play-cat-items.is-stacked {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  column-count: auto;
}

.play-stack {
  flex: 1 1 0;
  min-width: 0;
}

/* Columns meter (play.js): an upright light grey pill in the top-left
   corner holding a small ruler that runs top to bottom: ticks, longer at
   1, 2 and 3 columns (top, middle, bottom), and a dark bar marking the
   current one. Click or drag along it (it snaps), or use the arrow keys;
   the bar springs along and the ticks it passes darken in turn. Its
   accessible name is "Columns". Desktop only. */
.play-meter {
  position: fixed;
  top: 24px;
  left: 24px;
  z-index: 20;
  display: flex;
  justify-content: center;
  width: 24px;
  padding: 10px 0;
  box-sizing: border-box;
  border: 1px solid rgba(0, 0, 0, 0.05);
  border-radius: 999px;
  background: #F1F1F3;
  touch-action: none;
  user-select: none;
  cursor: ns-resize;
}

/* So it reads as a control: on hover the outline and ticks darken, and a
   label beside it names the current setting ("2 columns"). */
.play-meter {
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.play-meter::after {
  content: attr(aria-valuetext);
  position: absolute;
  left: calc(100% + 10px);
  top: calc(10px + var(--p) * 48px);
  transform: translate(-4px, -50%);
  white-space: nowrap;
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.6);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease, top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.play-meter:hover,
.play-meter:focus-visible {
  border-color: rgba(0, 0, 0, 0.18);
  background: #E9E9EC;
}

.play-meter:hover .play-meter-ticks i,
.play-meter:focus-visible .play-meter-ticks i {
  background: rgba(0, 0, 0, 0.3);
}

.play-meter:hover .play-meter-ticks i.major,
.play-meter:focus-visible .play-meter-ticks i.major {
  width: 9px;
  background: rgba(0, 0, 0, 0.55);
}

.play-meter:hover::after,
.play-meter:focus-visible::after {
  opacity: 1;
  transform: translate(0, -50%);
}

.play-meter:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.play-meter-ticks {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  width: 14px;
  height: 48px;
}

.play-meter-ticks i {
  width: 4px;
  height: 1.5px;
  border-radius: 1px;
  background: rgba(0, 0, 0, 0.18);
  transition: background-color 0.3s ease, width 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.play-meter-ticks i.major {
  width: 7px;
  background: rgba(0, 0, 0, 0.35);
}

.play-meter-ticks i.is-pass {
  width: 9px;
  background: rgba(0, 0, 0, 0.7);
}

/* The bar marking the current setting: rides along the ruler. */
.play-meter-mark {
  position: absolute;
  left: 50%;
  top: calc(10px + var(--p) * 48px);   /* --p: 0 to 1 down the 48px ruler */
  width: 12px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--ink);
  transform: translate(-50%, -50%);
  transition: top 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (prefers-reduced-motion: reduce) {
  .play-meter-mark {
    transition-duration: 0.01s;
  }
}

@media (max-width: 900px) {
  .play-meter {
    display: none;
  }
}

/* Masonry via natural image height (not a forced aspect-ratio box) — each
   tile is exactly as tall as its image wants to be at the column's fixed
   width, like huyml.co/playground's grid, so nothing gets cropped. */
.play-item {
  position: relative;
  margin: 0 0 20px;
  break-inside: avoid;
  border-radius: 2px;
  overflow: hidden;
  cursor: default;   /* only the tiles that link out are clickable */
  transform: scale(1);
  transform-origin: center;
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}

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

/* Drag placeholder used only by play-edit.js (?edit mode) while a tile
   is mid-drag — marks the slot it will drop into. */
.play-item-ghost {
  opacity: 0.3;
}

/* Scaling the whole tile (not just its image) so it visibly grows on
   hover — transform doesn't participate in layout, so the surrounding
   grid/columns never reflow. Kept small (1.03, within the 20px gap between tiles) since a bigger scale
   pushed the tile visibly over its neighbors, reading as a layout bug
   rather than an intentional hover state.

   Gated to devices with a real hover-capable pointer (mouse/trackpad):
   touch has no "hover then leave" — a tap satisfies :hover with nothing
   to naturally end it, so tiles were getting stuck scaled up after being
   tapped until something else on the page was touched. */
@media (hover: hover) and (pointer: fine) {
  .play-item:hover {
    transform: scale(var(--play-hover, 1.03));
    z-index: 5;
  }
}

.play-item--large {
  box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.25);
}

/* The one composite tile: a sharp photo layered in front of a softly
   blurred duplicate of another shot, offset behind it — echoes the
   "stack of prints" look from the Figma group without reproducing its
   exact multi-layer crop math. */
.play-stack {
  position: relative;
}

.play-stack-back {
  position: absolute;
  inset: 10px -10px -10px 10px;
  width: calc(100% - 0px);
  height: calc(100% - 0px);
  object-fit: cover;
  filter: blur(2px);
  opacity: 0.8;
  border-radius: 2px;
}

.play-stack-front {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px;
  box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25);
}

/* Below this width there's no room for a fixed left rail beside a
   multi-column grid — .play-side and everything inside it switches from
   fixed/absolute (Figma's exact px coordinates) to normal document flow,
   stacked above the grid, so heights are whatever the content actually
   needs instead of a guessed padding-top on the grid. */
@media (max-width: 900px) {
  .play-side {
    position: static;
    width: auto;
    height: auto;
    padding: 96px 24px 32px;
    display: flex;
    flex-direction: column;
    gap: 16px;
  }

  .play-index,
  .play-bio,
  .profile {
    position: static;
    width: auto;
  }

  .play-grid {
    margin-left: 0;
    padding: 0 24px 96px;
  }

  .play-cat-items {
    column-count: 2;
  }

  /* No corner to sit in here: the name heads its own category instead,
     pinned under the top of the screen while the category scrolls by. */
  .play-cat > * {
    grid-area: auto;
  }

  .play-cat + .play-cat {
    margin-top: 112px;
  }

  .play-cat-title {
    justify-self: stretch;
    width: auto;
    margin: 0 -24px 16px;
    text-align: left;
    padding: 12px 24px;
    top: 0;
    background: var(--bg, #FAFAFA);
    font-size: 12px;
  }
}

@media (max-width: 780px) {
  .play-side {
    padding-left: 24px;
    padding-right: 24px;
  }

  .play-grid {
    padding-left: 24px;
    padding-right: 24px;
  }

  .play-cat-items {
    column-count: 1;
  }

  /* Under the phone's fixed nav bar. */
  .play-cat-title {
    top: 49px;
  }
}

/* Touch screens have no hover, and the rail only ever mirrors the hovered
   tile, so it would just be an empty gap above the grid there. */
@media (max-width: 900px) and (hover: none), (max-width: 900px) and (pointer: coarse) {
  .play-side {
    display: none;
  }

  .play-grid {
    padding-top: 73px;
  }
}

/* Tiles that link out: the whole tile is the link. */
.play-item--link > a {
  display: block;
}

/* Over a linking tile (play.js): a pill with the tile's call to action in
   place of the cursor (the site's dot steps aside for any
   .view-cursor.visible). Mouse only. */
.play-view-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 10001;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 15px;
  border-radius: 999px;
  background: #1C1C1E;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: #FFFFFF;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.play-view-cursor svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.play-view-cursor.visible {
  opacity: 1;
}

.play-item--link {
  cursor: pointer;
}

/* A small round badge in the top-right corner of tiles that link out, with
   an outgoing arrow: quiet (translucent, soft grey) so it hints rather than
   shouts. Over the tile it firms up and the arrow nudges out. */
.play-link-badge {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);   /* a hairline edge, for white pictures */
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: rgba(0, 0, 0, 0.55);
  pointer-events: none;
  transition: background-color 0.25s ease, color 0.25s ease;
}

.play-link-badge svg {
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@media (hover: hover) and (pointer: fine) {
  .play-item--link:hover .play-link-badge {
    background: #FFFFFF;
    color: var(--ink);
  }

  .play-item--link:hover .play-link-badge svg {
    transform: translate(1.5px, -1.5px);
  }
}
