/* Works page: three-level browsing experience —
   1) an ambient-drifting Fiber-style 3D train of category cards
   2) either a pannable canvas (centered title + slotted project cards)
      or, for categories with layout:"gallery" in the CMS data, an
      Ether-style parallax column gallery of media tiles
   3) a staged-entrance project detail view

   Scoped to this page only via body.works-page so overflow:hidden and
   the mono body-text default don't leak into other pages. */

body.works-page {
  overflow: hidden;
}
body.works-page .sh-page {
  font-family: var(--sh-mono);
}

/* =========================================================
   LEVEL 1 — 3D CATEGORY TRAIN
========================================================= */
.deck-view {
  position: fixed;
  inset: 0;
  background: var(--sh-ink);
  transition: opacity 0.5s ease, filter 0.5s ease;
}
.deck-view.exit {
  opacity: 0;
  filter: blur(6px);
  pointer-events: none;
}

.deck-stage {
  position: absolute;
  inset: 0;
  perspective: 1600px;
  perspective-origin: 42% 44%;
  cursor: grab;
}
.deck-stage.dragging {
  cursor: grabbing;
}
.deck {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

.dcard {
  position: absolute;
  left: 5vw;
  top: 58%;
  width: clamp(270px, 29vw, 500px);
  aspect-ratio: 4/3;
  margin-top: calc(clamp(270px, 29vw, 500px) * -0.375);
  transform-style: preserve-3d;
  backface-visibility: hidden;
  will-change: transform, opacity, filter;
  cursor: pointer;
  user-select: none;
}
.dcard .face {
  position: absolute;
  inset: 0;
  border-radius: 10px;
  overflow: hidden;
  background: linear-gradient(155deg, var(--stop1), var(--stop2));
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.55);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.dcard img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  -webkit-user-drag: none;
}
.dcard .top-tag {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  padding: 16px 18px;
  font-size: 10px;
  letter-spacing: 0.16em;
  font-weight: 700;
  color: rgba(22, 17, 16, 0.6);
}
.dcard .tag {
  position: relative;
  z-index: 1;
  padding: 16px 18px;
  background: linear-gradient(0deg, rgba(22, 17, 16, 0.55), transparent);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.dcard .tag .nm {
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(18px, 2vw, 30px);
  color: var(--sh-bone);
}
.dcard .tag .ct {
  font-size: 11px;
  letter-spacing: 0.15em;
  color: var(--sh-orange-hot);
}

.intro {
  position: fixed;
  top: max(5vh, 6.5rem);
  left: 5vw;
  z-index: 10;
  max-width: 44ch;
  font-size: clamp(13px, 1.4vw, 17px);
  line-height: 1.65;
  color: var(--sh-bone);
}
.intro b {
  color: var(--sh-orange);
  font-weight: 500;
}
.deck-hint {
  position: fixed;
  bottom: 5vh;
  left: 5vw;
  z-index: 10;
  font-size: 10px;
  letter-spacing: 0.28em;
  color: var(--sh-taupe);
  animation: work-hint-pulse 2.4s ease-in-out infinite;
}
@keyframes work-hint-pulse {
  50% {
    opacity: 0.4;
  }
}
.deck-counter {
  position: fixed;
  bottom: 5vh;
  right: 5vw;
  z-index: 10;
  font-size: 12px;
  letter-spacing: 0.2em;
  color: var(--sh-taupe);
  text-align: right;
}
.deck-counter b {
  color: var(--sh-bone);
  font-size: 20px;
}
.deck-current {
  position: fixed;
  bottom: 10vh;
  right: 5vw;
  z-index: 10;
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(18px, 2.4vw, 34px);
  text-align: right;
  color: var(--sh-bone);
}
.deck-progress {
  position: fixed;
  left: 0;
  bottom: 0;
  z-index: 10;
  height: 3px;
  width: 100%;
  background: rgba(239, 230, 218, 0.06);
}
.deck-progress .fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--sh-orange), var(--sh-orange-hot));
  box-shadow: 0 0 14px rgba(255, 90, 31, 0.5);
}

/* =========================================================
   LEVEL 2 — CATEGORY CANVAS (flat drag world)
========================================================= */
.canvas-view {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--sh-ink);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.55s cubic-bezier(0.2, 1, 0.3, 1);
}
.canvas-view.open {
  opacity: 1;
  pointer-events: auto;
}

.works {
  position: absolute;
  inset: 0;
  cursor: grab;
  overflow: hidden;
}
.works.dragging {
  cursor: grabbing;
}
.world {
  position: absolute;
  width: 230vw;
  height: 280vh;
  will-change: transform;
}
.world-title {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(72px, 11.5vw, 220px);
  letter-spacing: -0.04em;
  white-space: nowrap;
  color: var(--sh-bone);
  user-select: none;
  pointer-events: none;
  z-index: 1;
}
.world-title .accent {
  color: var(--sh-orange);
}

.pcard {
  position: absolute;
  z-index: 2;
  user-select: none;
  -webkit-user-drag: none;
  cursor: pointer;
  /* entrance: staged pop when canvas opens */
  opacity: 0;
  scale: 0.85;
  transition: opacity 0.6s cubic-bezier(0.2, 1, 0.3, 1), scale 0.6s cubic-bezier(0.2, 1, 0.3, 1);
  transition-delay: var(--d, 0s);
}
.canvas-view.open .pcard {
  opacity: 1;
  scale: 1;
}
.pcard .frame {
  position: relative;
  overflow: hidden;
  background: linear-gradient(155deg, var(--stop1), var(--stop2));
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  transition: transform 0.5s cubic-bezier(0.2, 1, 0.3, 1), box-shadow 0.5s;
  display: flex;
  align-items: flex-end;
}
.pcard:hover .frame {
  transform: scale(1.035);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.65);
}
.pcard img,
.pcard video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.pcard .ptag {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: 14px 16px;
  background: linear-gradient(0deg, rgba(22, 17, 16, 0.55), transparent);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sh-bone);
  opacity: 0;
  translate: 0 6px;
  transition: opacity 0.4s, translate 0.4s;
}
.pcard:hover .ptag {
  opacity: 1;
  translate: 0 0;
}
.pcard .ptag .yr {
  color: var(--sh-orange-hot);
}
.pcard.s-tall .frame {
  width: clamp(170px, 16vw, 290px);
  aspect-ratio: 3/4;
}
.pcard.s-wide .frame {
  width: clamp(230px, 22vw, 410px);
  aspect-ratio: 16/10;
}
.pcard.s-sq .frame {
  width: clamp(160px, 14vw, 260px);
  aspect-ratio: 1;
}
/* video sizes: aspect-ratio matches the source clip's native ratio
   exactly, so object-fit:cover above needs no cropping to fill the
   frame — cover and contain produce the same result once the box
   ratio already equals the content ratio. */
.pcard.s-vland .frame {
  width: clamp(230px, 24vw, 440px);
  aspect-ratio: 16/9;
}
.pcard.s-vport .frame {
  width: clamp(150px, 13vw, 230px);
  aspect-ratio: 9/16;
}

.canvas-back {
  position: absolute;
  top: max(4vh, 6.5rem);
  left: 5vw;
  z-index: 60;
  background: var(--sh-panel);
  border: 1px solid rgba(239, 230, 218, 0.15);
  color: var(--sh-bone);
  font-family: var(--sh-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  padding: 12px 20px;
  border-radius: 999px;
  cursor: pointer;
  transition: border-color 0.3s, color 0.3s;
}
.canvas-back:hover {
  border-color: var(--sh-orange);
  color: var(--sh-orange-hot);
}
.canvas-crumb {
  position: absolute;
  top: max(5vh, 6.5rem);
  right: 5vw;
  z-index: 60;
  font-size: 10px;
  letter-spacing: 0.25em;
  color: var(--sh-taupe);
}
.canvas-crumb b {
  color: var(--sh-orange);
  font-weight: 500;
}
.canvas-hint {
  position: absolute;
  bottom: 5vh;
  left: 50%;
  translate: -50% 0;
  z-index: 60;
  font-size: 10px;
  letter-spacing: 0.25em;
  color: var(--sh-taupe);
  animation: work-hint-pulse 2.4s ease-in-out infinite;
}

/* =========================================================
   LEVEL 2B — GALLERY VIEW (Ether-style, layout:"gallery" only)
   vertical columns at different parallax speeds, statement line
   fixed in the center
========================================================= */
.gallery-view {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: #0d0a09;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.55s cubic-bezier(0.2, 1, 0.3, 1);
  overflow: hidden;
}
.gallery-view.open {
  opacity: 1;
  pointer-events: auto;
}

/* columns layer, moved by JS at different eased rates */
.g-cols {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1.4vw;
  padding: 0 1.4vw;
}
.g-col {
  display: flex;
  flex-direction: column;
  gap: 1.4vw;
  will-change: transform;
}
.g-tile {
  /* no explicit pointer-events here: it must inherit from .gallery-view,
     which is pointer-events:none while closed. An explicit auto here
     would override that and leave the previous gallery's (invisible,
     opacity:0) tiles still clickable on top of the train after close —
     the next click on a train card can land on a stale tile instead. */
  position: relative;
  border-radius: 0; /* hard Ether corners */
  overflow: hidden;
  background: linear-gradient(155deg, var(--stop1), var(--stop2));
  cursor: pointer;
  flex: 0 0 auto;
  /* Ether-style reveal: each tile DESCENDS into place when it enters
     the viewport — on open for visible tiles (staggered), then
     continuously as the user scrolls */
  opacity: 0;
  translate: 0 -32vh;
  transition: opacity 0.8s cubic-bezier(0.2, 1, 0.3, 1), translate 1.05s cubic-bezier(0.22, 1.1, 0.3, 1);
  transition-delay: var(--d, 0s);
}
.g-tile.in {
  opacity: 1;
  translate: 0 0;
}
.g-tile.t-tall {
  aspect-ratio: 9/14;
}
.g-tile.t-mid {
  aspect-ratio: 4/5;
}
.g-tile.t-sq {
  aspect-ratio: 1;
}
/* exact match to the real clips' native 9:16, so object-fit:cover below
   needs no crop — used instead of the decorative shapes whenever a tile
   is backed by an actual video */
.g-tile.t-vport {
  aspect-ratio: 9/16;
}
.g-tile img,
.g-tile video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  transition: transform 0.6s cubic-bezier(0.2, 1, 0.3, 1);
}
.g-tile:hover img,
.g-tile:hover video {
  transform: scale(1.05);
}
.g-tile .gt {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 12px 14px;
  background: linear-gradient(0deg, rgba(13, 10, 9, 0.65), transparent);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sh-bone);
  opacity: 0;
  translate: 0 6px;
  transition: opacity 0.35s, translate 0.35s;
}
.g-tile:hover .gt {
  opacity: 1;
  translate: 0 0;
}
.g-tile .gt .yr {
  color: var(--sh-orange-hot);
}
/* dim tiles slightly so the statement owns the frame */
.g-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(13, 10, 9, 0.22);
  transition: background 0.4s;
}
.g-tile:hover::after {
  background: rgba(13, 10, 9, 0);
}

/* fixed center statement */
.g-statement {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
  z-index: 5;
  padding: 0 6vw;
}
.g-statement .kick {
  font-size: clamp(9px, 1vw, 12px);
  letter-spacing: 0.4em;
  color: var(--sh-taupe);
  margin-bottom: 2vh;
  text-shadow: 0 2px 20px rgba(13, 10, 9, 0.9);
}
.g-statement h2 {
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(38px, 7vw, 110px);
  line-height: 0.98;
  letter-spacing: -0.01em;
  color: var(--sh-bone);
  text-shadow: 0 4px 40px rgba(13, 10, 9, 0.95), 0 0 80px rgba(13, 10, 9, 0.8);
}
.g-statement h2 .accent {
  color: var(--sh-orange);
}
.g-hint {
  position: absolute;
  bottom: 5vh;
  left: 50%;
  translate: -50% 0;
  z-index: 6;
  font-size: 10px;
  letter-spacing: 0.25em;
  color: var(--sh-taupe);
  animation: work-hint-pulse 2.4s ease-in-out infinite;
  pointer-events: none;
}

/* =========================================================
   LEVEL 3 — PROJECT DETAIL
========================================================= */
.detail {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--sh-ink);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  translate: 0 6vh;
  pointer-events: none;
  transition: opacity 0.6s cubic-bezier(0.2, 1, 0.3, 1), translate 0.6s cubic-bezier(0.2, 1, 0.3, 1);
}
.detail.open {
  opacity: 1;
  translate: 0 0;
  pointer-events: auto;
}
.detail-close {
  position: fixed;
  top: max(4vh, 6.5rem);
  right: 5vw;
  z-index: 95;
  background: var(--sh-panel);
  border: 1px solid rgba(239, 230, 218, 0.15);
  color: var(--sh-bone);
  font-family: var(--sh-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  padding: 12px 20px;
  border-radius: 999px;
  cursor: pointer;
  opacity: 0;
  transition: border-color 0.3s, color 0.3s, opacity 0.4s 0.25s;
}
.detail.open .detail-close {
  opacity: 1;
}
.detail-close:hover {
  border-color: var(--sh-orange);
  color: var(--sh-orange-hot);
}
.detail-inner {
  max-width: 1160px;
  margin: 0 auto;
  padding: 14vh 6vw 10vh;
}
.detail-inner > * {
  opacity: 0;
  translate: 0 26px;
  transition: opacity 0.7s cubic-bezier(0.2, 1, 0.3, 1), translate 0.7s cubic-bezier(0.2, 1, 0.3, 1);
}
.detail.open .detail-inner > * {
  opacity: 1;
  translate: 0 0;
}
.detail.open .detail-inner > *:nth-child(1) {
  transition-delay: 0.15s;
}
.detail.open .detail-inner > *:nth-child(2) {
  transition-delay: 0.22s;
}
.detail.open .detail-inner > *:nth-child(3) {
  transition-delay: 0.3s;
}
.detail.open .detail-inner > *:nth-child(4) {
  transition-delay: 0.38s;
}
.detail.open .detail-inner > *:nth-child(5) {
  transition-delay: 0.46s;
}
.detail.open .detail-inner > *:nth-child(6) {
  transition-delay: 0.54s;
}

.d-eyebrow {
  font-size: 11px;
  letter-spacing: 0.3em;
  color: var(--sh-taupe);
  margin-bottom: 16px;
}
.d-eyebrow b {
  color: var(--sh-orange);
  font-weight: 500;
}
.d-title {
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(42px, 8vw, 110px);
  line-height: 0.95;
  letter-spacing: -0.02em;
  margin-bottom: 6vh;
  color: var(--sh-bone);
}
.d-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  padding: 28px 0;
  border-top: 1px solid rgba(239, 230, 218, 0.1);
  border-bottom: 1px solid rgba(239, 230, 218, 0.1);
  margin-bottom: 6vh;
}
.d-meta .cell h5 {
  font-size: 9px;
  letter-spacing: 0.3em;
  color: var(--sh-taupe);
  text-transform: uppercase;
  font-weight: 500;
  margin-bottom: 10px;
}
.d-meta .cell div {
  font-size: 14px;
  letter-spacing: 0.03em;
  color: var(--sh-bone);
}
.d-hero {
  width: 100%;
  aspect-ratio: 16/9;
  background: linear-gradient(155deg, var(--stop1, #2a2019), var(--stop2, #4a3527));
  border-radius: 12px;
  overflow: hidden;
  position: relative;
  margin-bottom: 6vh;
}
.d-hero img,
.d-hero video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* a portrait clip in the default 16:9 box would need heavy letterboxing
   to avoid cropping — instead the box itself switches to a narrow 9:16
   shape (matching the s-vport clips exactly, so cover above still needs
   no crop) and centers, rather than spanning the full content width. */
.d-hero.portrait {
  aspect-ratio: 9/16;
  max-width: min(420px, 70vw);
  margin-left: auto;
  margin-right: auto;
}
.d-hero .tc {
  position: absolute;
  top: 18px;
  right: 20px;
  font-size: 10px;
  letter-spacing: 0.16em;
  color: rgba(239, 230, 218, 0.8);
  background: rgba(22, 17, 16, 0.45);
  padding: 6px 12px;
  border-radius: 4px;
}
.d-hero-sound {
  position: absolute;
  z-index: 2;
  top: 18px;
  left: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(22, 17, 16, 0.55);
  border: 1px solid rgba(239, 230, 218, 0.25);
  color: var(--sh-bone);
  cursor: pointer;
  transition: border-color 0.3s, color 0.3s;
}
.d-hero-sound:hover {
  border-color: var(--sh-orange);
  color: var(--sh-orange-hot);
}
.d-hero-sound .ico {
  width: 16px;
  height: 16px;
}
.d-hero-sound .ico.off {
  display: none;
}
.d-hero-sound.is-muted .ico.on {
  display: none;
}
.d-hero-sound.is-muted .ico.off {
  display: block;
}
.d-body {
  display: grid;
  grid-template-columns: 1fr 1.6fr;
  gap: 5vw;
  margin-bottom: 8vh;
}
.d-body h4 {
  font-family: var(--sh-display);
  font-weight: 800;
  font-size: clamp(18px, 2vw, 26px);
  color: var(--sh-bone);
}
.d-body p {
  font-size: 14px;
  line-height: 1.8;
  color: var(--sh-taupe);
}
.d-next {
  border-top: 1px solid rgba(239, 230, 218, 0.1);
  padding-top: 6vh;
  text-align: center;
  cursor: pointer;
}
.d-next .lbl {
  font-size: 10px;
  letter-spacing: 0.3em;
  color: var(--sh-taupe);
  margin-bottom: 14px;
}
.d-next .nm {
  font-family: var(--sh-display);
  font-weight: 900;
  font-size: clamp(30px, 5vw, 64px);
  color: var(--sh-bone);
  transition: color 0.3s;
}
.d-next:hover .nm {
  color: var(--sh-orange);
}

/* =========================================================
   MOBILE — vertical lists, no 3D, no drag worlds, no parallax
========================================================= */
@media (max-width: 820px) {
  body.works-page {
    overflow: auto;
  }

  /* ---- level 1: train -> plain vertical list ---- */
  .deck-view {
    overflow-y: auto;
  }
  .deck-stage {
    position: static;
    perspective: none;
    cursor: auto;
    padding: 16vh 6vw 10vh;
  }
  .deck {
    position: static;
    transform-style: flat;
  }
  .dcard {
    position: static;
    width: 100%;
    margin: 0 0 6vw;
    transform: none !important;
    opacity: 1 !important;
    filter: none !important;
  }
  .intro,
  .deck-hint,
  .deck-current,
  .deck-counter,
  .deck-progress {
    display: none;
  }

  /* ---- level 2: canvas -> plain vertical list ---- */
  .works {
    position: static;
    overflow: visible;
    cursor: auto;
    padding: 14vh 6vw 8vh;
  }
  .world {
    position: static;
    width: auto;
    height: auto;
    transform: none !important;
  }
  .world-title {
    position: static;
    translate: 0 0;
    font-size: 16vw;
    white-space: normal;
    margin-bottom: 6vw;
  }
  .pcard {
    position: static;
    display: block;
    margin: 0 0 6vw;
    opacity: 1;
    scale: 1;
  }
  .pcard .frame {
    width: 100% !important;
  }
  .canvas-view {
    position: fixed;
    inset: 0;
    overflow-y: auto;
  }
  /* .canvas-back/-crumb (shared by the gallery's back/crumb too) are
     position:absolute, anchored to their view box, which pans via a JS
     transform on desktop. On mobile that view scrolls for real instead,
     so absolute chrome would either scroll away with the list (the
     back button) or land mid-scroll as a stray floating block (the
     hint/crumb, redundant anyway with the always-visible title on a
     plain list). Fixing the back button keeps the way out reachable at
     any scroll position, matching how .detail-close already behaves. */
  .canvas-back {
    position: fixed;
  }
  .canvas-hint,
  .canvas-crumb {
    display: none;
  }

  /* ---- level 2b: gallery -> 2-column list, parallax + reveal off ----
     gLoop() already skips column transforms when isMobile(), and the
     .g-tile rule below forces the resting opacity/translate, so
     parallax and the descent choreography are both off. What's left is
     making the result an actual scrollable list: .g-cols was
     position:absolute+inset:0 (clipped to exactly the gallery-view
     box), so it needs to rejoin normal flow, and the statement (which
     sits *after* .g-cols in the DOM) needs to visually lead instead of
     trail it — done by making gallery-view a flex column and pulling
     the statement in front with `order`. */
  .gallery-view {
    overflow-y: auto;
    display: flex;
    flex-direction: column;
  }
  .g-statement {
    order: -1;
    position: static;
    flex: 0 0 auto;
    padding: 16vh 6vw 4vh;
  }
  .g-statement h2 {
    font-size: 11vw;
  }
  .g-cols {
    position: static;
    flex: 1 1 auto;
    grid-template-columns: repeat(2, 1fr);
    padding: 0 4vw 8vh;
  }
  .g-col {
    padding-top: 0 !important;
    transform: none !important;
  }
  .g-col:nth-child(n + 3) {
    display: none;
  }
  .g-tile {
    opacity: 1 !important;
    translate: 0 0 !important;
  }
  .g-hint {
    display: none;
  }

  .d-meta {
    grid-template-columns: 1fr;
    gap: 18px;
  }
  .d-body {
    grid-template-columns: 1fr;
    gap: 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .g-tile {
    transition: none;
  }
  .g-tile img,
  .g-tile video {
    transition: none;
  }
}
