/* ============================================================================
   detail.css — the click-through layer for a project.

   Learned from watching jesperlandberg.com/projects/<slug> as a frame sequence,
   not from its markup: clicking a card in the carousel ROUTES to a full-screen
   cream panel — oversized title top-left, a short description, a row of meta
   chips, and a right-hand column of full-bleed captures of the actual site
   scrolling past. It is not an overlay and not a modal: the carousel is gone,
   replaced wholesale.

   Ours is a text case study at /work/<slug> — good words, no pictures. That is
   the right page for someone who wants to read how it was built, and the wrong
   page for someone who just scrolled past a video of the thing and wants to see
   it properly. So: keep the case study, and add this as the thing you get when
   you click the card itself.

   Deliberately not a <dialog>. A dialog traps focus, dims the page behind it
   and puts a scrim over the carousel — all of which say "temporary". This is a
   destination. It gets its own URL (#project-slug), it is a real page state you
   can link to and go back from, and it does not dim what came before it.
   ========================================================================= */

.gallery-detail {
  position: fixed;
  inset: 0;
  /* Above the sticky site header, which sits far higher than 90 on this page.
     At 90 the close button rendered behind it and the title was clipped by it —
     found by looking at a screenshot of the open layer, not by a test, because
     every assertion about the layer passed while it was visibly broken. */
  z-index: 400;
  /* Hidden by default. The [hidden] attribute is what removes it from the a11y
     tree and from tab order; the transition only runs on the way in and out. */
  opacity: 0;
  pointer-events: none;
  background: var(--detail-bg);
  color: var(--detail-ink);
  overflow: hidden;
  transition: opacity .5s var(--ease);
  font-family: 'Bricolage Grotesque', sans-serif;
}

.gallery-detail[hidden] {
  display: none;
}

.gallery-detail.is-open {
  opacity: 1;
  pointer-events: auto;
}

/* --- close --- */

/* z-index must beat the site header.

   Measured, not assumed: the close button was invisible on open because the
   sticky header paints at a higher layer, and the title was clipped underneath
   it for the same reason. The header is z-index well above 90 on this site, so
   the layer needs to clear it. */
.gallery-detail-close {
  position: absolute;
  top: clamp(18px, 3vh, 34px);
  right: clamp(18px, 3vw, 40px);
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--detail-line);
  /* Opaque, not transparent: the header shows through it otherwise. */
  background: rgba(18, 10, 23, .8);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--detail-ink);
  cursor: pointer;
  z-index: 4;
  transition: background .3s var(--ease), color .3s var(--ease), transform .3s var(--ease);
}

.gallery-detail-close:hover {
  background: var(--detail-ink);
  color: var(--detail-bg);
  transform: rotate(90deg);
}

.gallery-detail-close svg {
  width: 15px;
  height: 15px;
}

/* --- two columns: the words hold, the work scrolls --- */

/* Text left, captures right — but the text column does not need to be a third of
   the width to hold a paragraph and two buttons. It was, and that left the
   capture pair squeezed into 950px with a dead band of empty space beneath it.
   30% of the viewport for prose, the rest for the work. */
.gallery-detail-inner {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: minmax(280px, 30%) 1fr;
  height: 100%;
}

.gallery-detail-text {
  /* Top padding clears the sticky header AND the close button, both of which sit
     over this column. It was `clamp(28px, 6vh, 90px)` and the oversized title
     was clipped in half by the header painted on top of it. */
  padding: clamp(96px, 13vh, 148px) clamp(28px, 4vw, 70px) clamp(32px, 6vh, 70px);
  display: grid;
  align-content: start;
  gap: 20px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.gallery-detail-kind {
  margin: 0;
  font: 600 10px/1 'Manrope', sans-serif;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--detail-accent);
}

.gallery-detail-title {
  margin: 0;
  font-weight: 500;
  font-size: clamp(38px, 4.6vw, 78px);
  line-height: .95;
  letter-spacing: -.035em;
  text-wrap: balance;
}

.gallery-detail-blurb {
  margin: 0;
  max-width: 38ch;
  font-family: 'Manrope', sans-serif;
  font-size: clamp(14px, 1.05vw, 17px);
  line-height: 1.6;
  color: var(--detail-muted);
  text-wrap: pretty;
}

/* Meta chips. Reference puts them under the description as small pills; the
   content is the same, the tone is quieter than a badge. */
.gallery-detail-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.gallery-detail-meta li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 100px;
  border: 1px solid var(--detail-line);
  font: 500 11px/1 'Manrope', sans-serif;
  letter-spacing: .04em;
  color: var(--detail-muted);
  white-space: nowrap;
}

.gallery-detail-meta svg {
  width: 12px;
  height: 12px;
  opacity: .7;
}

/* --- actions --- */

.gallery-detail-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 12px;
}

.gallery-detail-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 20px;
  border-radius: 100px;
  border: 1px solid var(--detail-ink);
  background: transparent;
  color: var(--detail-ink);
  font: 600 12px/1 'Manrope', sans-serif;
  letter-spacing: .05em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease);
}

.gallery-detail-btn svg {
  width: 14px;
  height: 14px;
  transition: transform .3s var(--ease);
}

.gallery-detail-btn:hover {
  background: var(--detail-ink);
  color: var(--detail-bg);
}

.gallery-detail-btn:hover svg {
  transform: translate(2px, -2px);
}

.gallery-detail-btn--solid {
  background: var(--detail-accent);
  border-color: var(--detail-accent);
  color: var(--detail-bg);
}

.gallery-detail-btn--solid:hover {
  background: var(--detail-ink);
  border-color: var(--detail-ink);
}

/* --- the capture column --- */

/* Full-bleed captures of the actual site, scrolling. This is the reason the
   layer exists: the carousel shows the site moving, this shows it still and
   large enough to read. */
/* The capture column.

   Desktop + phone SIDE BY SIDE rather than stacked, because that is the argument
   the card makes and the layer should make it louder: the same build at two
   sizes, in one glance. Stacked they were 6 screens tall and the scroll cue was
   pointing at a great deal of nothing. */
.gallery-detail-shots {
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Vertical centring, so the captures sit in the middle of the column instead
     of hanging from the top with a band of dead space beneath — 300px of it at
     1440x900, visible in the screenshot. */
  padding: clamp(84px, 11vh, 130px) clamp(24px, 3.4vw, 60px) clamp(56px, 8vh, 96px);
  display: grid;
  gap: clamp(22px, 3vh, 40px);
  align-content: center;
}

.gallery-detail-group {
  display: grid;
  gap: 14px;
}

.gallery-detail-group[hidden] {
  display: none;
}

/* The group label repeats the project title that is already set in massive type
   two inches to the left. On a wide screen that reads as a stray floating
   fragment rather than a heading — it sat alone above the captures with the
   big title nowhere near it. Dropped entirely: the layer already says which
   project you are looking at, twice, in two places. */
.gallery-detail-groupLabel {
  display: none;
}

/* Desktop and phone side by side, the phone as a phone.

   Equal columns made the phone capture 230px wide, which is roughly the size it
   is in the carousel — too small to read anything, which defeats the point of
   opening the layer. The phone is held at its own natural aspect ratio and
   given a portrait frame, so it reads as "this is the mobile build" at a size
   you can actually see, and the pair sits on one baseline instead of leaving
   half the column empty. */
.gallery-detail-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(14px, 1.8vw, 28px);
  /* BOTTOM aligned, so both captures sit on the same floor line the way the
     carousel card does. Centre alignment left the phone floating above the
     desktop with a gap under it — visible in the screenshot, and not caught by
     any assertion, because the assertions only checked the pair existed. */
  align-items: end;
}

.gallery-detail-pair .gallery-detail-shot:first-child {
  aspect-ratio: 8 / 5;
}

.gallery-detail-pair .gallery-detail-shot:last-child {
  /* A phone is 390x844. At ~13vw this lands around 190x410 on a 1440 screen —
     twice the carousel's size and finally legible. */
  width: clamp(150px, 13vw, 210px);
  aspect-ratio: 390 / 844;
}

.gallery-detail-shot {
  position: relative;
  scroll-snap-align: start;
  border-radius: 14px;
  overflow: hidden;
  background: #0b0710;
  border: 1px solid var(--detail-line);
  aspect-ratio: 8 / 5;
}

.gallery-detail-shot video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}

.gallery-detail-shot figcaption {
  position: absolute;
  inset: auto 0 0;
  padding: 22px 18px 14px;
  font: 500 11px/1 'Manrope', sans-serif;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #f6eee9;
  background: linear-gradient(to top, rgba(11, 7, 16, .9), transparent);
}

/* A quiet caption, not a scroll prompt.

   This was "Scroll for the full build" with a bouncing arrow, inherited from
   the reference's taller capture column. Once the desktop and phone captures
   were put side by side they fit in one screen, so there was nothing to scroll
   — and a cue promising scrolling that does not exist is worse than no cue. It
   now says what you are actually looking at, which is also the argument the
   layer is making. */
.gallery-detail-cue {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(16px, 2.6vh, 30px);
  text-align: center;
  margin: 0;
  font: 500 10px/1 'Manrope', sans-serif;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--detail-muted);
  opacity: .7;
  z-index: 3;
  pointer-events: none;
}

.gallery-detail-cue.is-gone {
  opacity: 0;
}

/* On a wide screen the capture column was bottom-anchored, so the pair sat low
   and left a band of dead space beneath the text column's buttons. Pinning the
   text column's content to the middle of its own space puts the words on the
   same optical line as the work. `align-self` on the grid child, not a transform
   — a transform would detach it from the scroll flow. */
.gallery-detail-text {
  align-content: center;
}

/* --- the entrance --- */

/* Reference fades the whole panel up. So does this — but the captures arrive
   slightly after the words, staggered, so the page assembles instead of
   appearing. That is the difference between a transition and a reveal. */
.gallery-detail.is-open .gallery-detail-title,
.gallery-detail.is-open .gallery-detail-blurb,
.gallery-detail.is-open .gallery-detail-meta,
.gallery-detail.is-open .gallery-detail-actions {
  animation: gallery-detail-rise .8s var(--ease) both;
}

.gallery-detail.is-open .gallery-detail-title { animation-delay: .06s; }
.gallery-detail.is-open .gallery-detail-blurb { animation-delay: .12s; }
.gallery-detail.is-open .gallery-detail-meta { animation-delay: .18s; }
.gallery-detail.is-open .gallery-detail-actions { animation-delay: .24s; }

.gallery-detail.is-open .gallery-detail-pair {
  animation: gallery-detail-shot .9s var(--ease) both;
  animation-delay: .18s;
}

@keyframes gallery-detail-rise {
  from { opacity: 0; transform: translate3d(0, 22px, 0); }
  to { opacity: 1; transform: none; }
}

@keyframes gallery-detail-shot {
  from { opacity: 0; transform: translate3d(0, 30px, 0) scale(.985); }
  to { opacity: 1; transform: none; }
}

/* --- phone: one column, words first, captures below --- */

@media (max-width: 900px) {
  .gallery-detail {
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .gallery-detail-inner {
    position: static;
    display: block;
    height: auto;
  }

  .gallery-detail-text {
    overflow: visible;
    padding: 78px 6% 26px;
  }

  .gallery-detail-shots {
    overflow: visible;
    padding: 0 6% 96px;
    scroll-snap-type: none;
  }

  .gallery-detail-cue {
    position: static;
    text-align: left;
    padding: 0 6% 30px;
  }

  .gallery-detail-close {
    top: 16px;
    right: 16px;
    width: 42px;
    height: 42px;
  }
}

/* Reduced motion: the panel still opens, it just does not perform. The reveal
   animations are the only motion in here, so removing them removes all of it. */
@media (prefers-reduced-motion: reduce) {
  .gallery-detail,
  .gallery-detail.is-open .gallery-detail-title,
  .gallery-detail.is-open .gallery-detail-blurb,
  .gallery-detail.is-open .gallery-detail-meta,
  .gallery-detail.is-open .gallery-detail-actions,
  .gallery-detail.is-open .gallery-detail-shot {
    animation: none !important;
    transition: none !important;
  }

  .gallery-detail-cue svg {
    animation: none !important;
  }
}
