/* cases.css — case cards (#cases) and the large image viewer. Script: js/cases.js */

/* ---------- Cards: 1 column on mobile; from 768px the first two large, then rows of three ---------- */

.cases {
  display: grid;
  gap: var(--space-7) var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 768px) {
  .cases {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .cases > li {
    grid-column: span 2;
  }

  .cases > li:nth-child(-n+2) {
    grid-column: span 3;
  }
}

/* Image box: 4:5 like the pictures, so they fill it with only a sliver cropped.
   The colour thumbnail sits under a black-and-white cover (js/cases.js). */
.case__media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--color-surface);
  cursor: zoom-in;
}

.case__img,
.case__cover {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Only the cover's opacity changes, so the fade stays on the compositor (60fps
   on phones); the greyscale filter itself never animates. Reduced motion sets
   the duration to 0 (tokens.css): the colour switches at once. */
.case__cover {
  transition: opacity var(--duration-slow) var(--ease-out);
}

/* No cover image in cases.json: the thumbnail itself in black and white */
.case__cover--mono {
  filter: grayscale(1);
}

/* Colour: on keyboard focus everywhere (.is-focus), on hover with a mouse,
   and on touch screens while the card is mid-screen (.is-color), js/cases.js */
.case.is-focus .case__cover {
  opacity: 0;
}

@media (hover: hover) and (pointer: fine) {
  .case:hover .case__cover {
    opacity: 0;
  }
}

@media (hover: none), (pointer: coarse) {
  .case.is-color .case__cover {
    opacity: 0;
  }
}

/* Each card fills its grid row and "View larger" sits at the bottom, so the
   buttons in a row line up even when one industry name wraps to two lines */
.cases > li,
.case {
  display: flex;
  flex-direction: column;
}

.case {
  flex: 1;
}

.case__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
  margin-top: var(--space-4);
}

.case__title {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
}

.case__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin-top: auto;
  margin-left: calc(-1 * var(--space-2));
  padding: 0 var(--space-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-sm);
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.case__link:hover {
  color: var(--color-text-muted);
}

.case__link:active {
  transform: translateY(1px);
}

/* ---------- Viewer: large image over a dark surround ---------- */

html.is-viewer-open {
  overflow: hidden;
}

.viewer {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: var(--space-4);
  border: 0;
  background: var(--color-backdrop);
  color: var(--color-on-backdrop);
  overscroll-behavior: contain;
}

.viewer[open] {
  display: flex;
  align-items: center;
  justify-content: center;
  animation: viewer-in var(--duration-base) var(--ease-out);
}

.viewer::backdrop {
  background: transparent;
}

@keyframes viewer-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.viewer {
  /* Width / height of the image shown, set by js/viewer.js (e.g. 0.8 for a 4:5 case image) */
  --viewer-ratio: 1;
  /* Height kept free for the caption row (and the paging row when paged) */
  --viewer-room: var(--space-10);
}

.viewer.viewer--paged {
  --viewer-room: calc(var(--space-10) + 52px);
}

/* Case images: the caption stacks up to four lines (title, description, note, AI notice),
   under the paging row */
.viewer.viewer--details {
  --viewer-room: calc(var(--space-10) + var(--space-8));
}

.viewer.viewer--paged.viewer--details {
  --viewer-room: calc(var(--space-10) + var(--space-8) + 52px);
}

.viewer__figure {
  /* As large as fits the screen above the caption, keeping the image's shape */
  width: min(calc(100vw - 2 * var(--space-4)), calc((100vh - var(--viewer-room)) * var(--viewer-ratio)));
  width: min(calc(100vw - 2 * var(--space-4)), calc((100dvh - var(--viewer-room)) * var(--viewer-ratio)));
  margin: 0;
}

/* Sideways swipes page (js/viewer.js); vertical pans and pinch zoom stay with the browser */
.viewer__frame {
  position: relative;
  touch-action: pan-y pinch-zoom;
}

/* "Watch the film" on the look book's back cover, centred as on the book */
.viewer__film {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.viewer__film:active {
  transform: translate(-50%, calc(-50% + 1px));
}

.viewer__film[hidden] {
  display: none;
}

.viewer__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: var(--viewer-ratio);
  object-fit: contain;
  background: var(--color-video);
  user-select: none;
  -webkit-user-drag: none;
}

/* ---------- Paging (look book) ---------- */

/* Quick repeated taps on the controls page through the book; they must never
   become the iPhone's double-tap zoom (pinch zoom on the image is untouched) */
.viewer__nav,
.viewer__caption {
  touch-action: manipulation;
}

.viewer__nav {
  display: flex;
  margin-top: var(--space-2);
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-xs);
  color: var(--color-on-backdrop-muted);
}

.viewer__nav[hidden] {
  display: none;
}

.viewer__count {
  font-variant-numeric: tabular-nums;
}

.viewer__btn {
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--space-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-on-backdrop);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.viewer__btn:first-child {
  margin-left: calc(-1 * var(--space-2));
}

.viewer__btn:last-child {
  margin-right: calc(-1 * var(--space-2));
}

.viewer__btn:hover {
  color: var(--color-on-backdrop-muted);
}

.viewer__btn:focus-visible {
  outline: 2px solid var(--color-on-backdrop);
  outline-offset: 2px;
}

.viewer__btn:active {
  transform: translateY(1px);
}

.viewer__btn:disabled {
  color: var(--color-on-backdrop-muted);
  opacity: 0.4;
  cursor: default;
  transform: none;
}

.viewer__caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 44px;
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-on-backdrop-muted);
}

.viewer__title {
  color: var(--color-on-backdrop);
  font-weight: var(--weight-medium);
}

/* Look book: "Visual Lookbook · Art-directed AI imagery" on one line */
.viewer__ai::before {
  content: "· ";
}

/* Case images: title and description at reading size, then the reference note
   and AI notice smaller and dimmer */
.viewer--details .viewer__caption {
  align-items: flex-start;
}

.viewer--details .viewer__text > span {
  display: block;
}

.viewer--details .viewer__text > [hidden] {
  display: none;
}

.viewer--details .viewer__title,
.viewer--details .viewer__desc {
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

.viewer--details .viewer__desc {
  margin-top: var(--space-1);
  color: var(--color-on-backdrop);
}

.viewer--details .viewer__note {
  margin-top: var(--space-2);
}

.viewer--details .viewer__note:not([hidden]) + .viewer__ai {
  margin-top: 0;
}

.viewer--details .viewer__ai {
  margin-top: var(--space-2);
}

.viewer--details .viewer__ai::before {
  content: none;
}

/* The 44px Close starts below the image, with the caption's gap, its text
   centred in it; the caption text moves down so the title shares Close's line.
   The focus ring is drawn inside so it never reaches the image.
   The caption keeps the height of the longest one (a two-line description and a
   note), so paging between cases never moves the image or the paging row: the
   whole block is centred on the screen. */
@media not ((min-width: 768px) and (min-aspect-ratio: 5/4)) {
  .viewer--details .viewer__text {
    min-height: calc(var(--space-9) + var(--space-5));
    padding-top: var(--space-3);
  }

  .viewer--details .viewer__close:focus-visible {
    outline-offset: -2px;
  }
}

.viewer__close {
  min-width: 44px;
  min-height: 44px;
  margin-right: calc(-1 * var(--space-2));
  padding: 0 var(--space-2);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-on-backdrop-muted);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-out);
}

.viewer__close:hover,
.viewer__close:focus-visible {
  color: var(--color-on-backdrop);
}

.viewer__close:focus-visible {
  outline: 2px solid var(--color-on-backdrop);
  outline-offset: 2px;
}

.viewer__close:active {
  transform: translateY(1px);
}

/* ---------- Wide screens: the image fills the screen height ----------
   Every control moves to the empty sides, never over the image:
   Previous / Next as tall click areas on either side, Close beside the image's
   top right corner on the same line as Next, page count and caption in the
   bottom right corner (a case image's caption in the bottom left). "Watch the film" stays centred on the back cover. */

@media (min-width: 768px) and (min-aspect-ratio: 5/4) {
  .viewer {
    --wide-pad: var(--space-4);
    --wide-side: 240px;            /* the image shrinks before a side gets narrower */
    --wide-gap: var(--space-5);    /* image edge to the Previous / Next / Close text */
    --wide-hit: 160px;             /* width of the Previous / Next click areas */
    --wide-img-h: min(
      calc(100vh - 2 * var(--wide-pad)),
      calc((100vw - 2 * var(--wide-side)) / var(--viewer-ratio))
    );
    --wide-img-h: min(
      calc(100dvh - 2 * var(--wide-pad)),
      calc((100vw - 2 * var(--wide-side)) / var(--viewer-ratio))
    );
    box-sizing: border-box;
    padding: var(--wide-pad);
  }

  .viewer[open] {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    grid-template-rows: auto 1fr auto auto;
  }

  /* Flatten the markup so each piece sits on the dialog's grid */
  .viewer__figure,
  .viewer__caption,
  .viewer__nav:not([hidden]) {
    display: contents;
  }

  .viewer__frame {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: center;
  }

  .viewer__img {
    width: auto;
    height: var(--wide-img-h);
  }

  /* Previous / Next: the click area runs from the image edge outwards, from just
     under Close down to just above the page count, so a near miss lands neither
     on the backdrop (which closes the viewer) nor on Close */
  .viewer [data-viewer="prev"],
  .viewer [data-viewer="next"] {
    grid-row: 2;
    align-self: stretch;
    margin-top: var(--space-2);
    display: flex;
    align-items: center;
    width: min(var(--wide-hit), 100%);
    margin-left: 0;
    margin-right: 0;
    padding: 0 var(--wide-gap);
    color: var(--color-on-backdrop-muted);
    font-size: var(--text-base);
    text-underline-offset: 4px;
  }

  .viewer [data-viewer="prev"] {
    grid-column: 1;
    justify-self: end;
    justify-content: flex-end;
  }

  .viewer [data-viewer="next"] {
    grid-column: 3;
    justify-self: start;
    justify-content: flex-start;
  }

  .viewer [data-viewer]:hover:not(:disabled),
  .viewer [data-viewer]:focus-visible {
    color: var(--color-on-backdrop);
    text-decoration: underline;
  }

  .viewer [data-viewer]:focus-visible {
    outline-offset: -2px;
  }

  /* Close: beside the image's top right corner, its text on Next's line */
  .viewer__close {
    grid-column: 3;
    grid-row: 1;
    justify-self: start;
    align-self: start;
    /* Text lines up with Next's text; top lines up with the image's top edge
       (lower than the grid's top only when a square image is height-capped) */
    margin: 0 0 0 calc(var(--wide-gap) - var(--space-2));
    margin-top: calc((100vh - 2 * var(--wide-pad) - var(--wide-img-h)) / 2);
    margin-top: calc((100dvh - 2 * var(--wide-pad) - var(--wide-img-h)) / 2);
  }

  .viewer__count {
    grid-column: 3;
    grid-row: 3;
    justify-self: end;
    margin-bottom: var(--space-1);
    font-size: var(--text-xs);
    color: var(--color-on-backdrop-muted);
  }

  .viewer__text {
    grid-column: 3;
    grid-row: 4;
    justify-self: end;
    max-width: 100%;
    padding-left: var(--wide-gap); /* wraps before it reaches the image */
    text-align: right;
    font-size: var(--text-xs);
    color: var(--color-on-backdrop-muted);
  }

  /* Case images: the stacked caption sits in the bottom left corner instead,
     left-aligned, under the Previous click area. Its band has a fixed height
     (the longest caption, wrapped, fits), so neither Previous / Next nor the
     page count moves when a case's caption has more or fewer lines. The page
     count sits at the band's bottom, on the line of "Art-directed AI imagery". */
  .viewer--details[open] {
    grid-template-rows: auto 1fr minmax(calc(var(--space-9) + var(--space-3)), auto);
  }

  .viewer--details .viewer__count {
    align-self: end;
    margin-bottom: 0;
  }

  .viewer--details .viewer__text {
    grid-row: 3;
    align-self: end;
    grid-column: 1;
    justify-self: start;
    padding-left: 0;
    padding-right: var(--wide-gap);
    text-align: left;
  }
}
