@font-face {
  font-family: "Yetson Sans";
  src: url("fonts/YetsonSansWeb-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --color-home-bg: #fbfbfa;
  --color-work-bg: #fbfbfa;
  --color-red: #ff2424;

  --row-width: min(1400px, 72.92vw);
  --row-inset: 40px;
  --row-side: 50px;
  --row-size: 21px;
  --row-leading: 24px;
  --row-tracking: -1.05px;

  --adi-w: 262.58px;
  --adi-h: 93.802px;
  --segal-w: 264.443px;
  --segal-h: 102.411px;
  --segal-offset: 27.589px;
  --split-gap: 18.571px;
  --tags-size: 24px;
  --tags-leading: 26px;
  --tags-tracking: -1.2px;

  /* Logo scroll states: centred on the home page → compact in the work page header */
  --logo-base-scale: 1;
  --logo-compact-scale: 0.23077;
  --logo-compact-y: calc(var(--row-inset) + 12px);

  /* Welcome photo scales from 1 to (1 - this) between home and work */
  --photo-shrink: 0.3;

  /* How far below its place each gallery image starts before floating in */
  --gallery-rise: 35svh;

  /* Gallery unit: one Figma pixel of the 1080px-tall frame */
  --u: calc(100svh / 1080);

  /* Set by script.js: 0 on the home page, 1 on the work page */
  --p: 0;
  --close: 0;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* The document itself never scrolls: mobile Safari / Chrome resize their toolbars only when it
   does, which made the layout jump. All scrolling happens inside .page instead. */
html,
body {
  height: 100%;
  overflow: hidden;
}

.page {
  position: fixed;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: none;
  scroll-snap-type: y mandatory;
}

.page:focus {
  outline: none;
}

@media (prefers-reduced-motion: no-preference) {
  .page {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--color-home-bg);
  color: var(--color-red);
  font-family: "Yetson Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700;
  -webkit-font-smoothing: antialiased;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Shared text rows & links ---------- */

.home-nav,
.home-tagline,
.work-nav {
  font-size: var(--row-size);
  line-height: var(--row-leading);
  letter-spacing: var(--row-tracking);
  text-transform: uppercase;
  white-space: nowrap;
}

.nav-link {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-decoration: none;
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
  cursor: pointer;
}

.nav-link:hover,
.nav-link:focus-visible {
  text-decoration-line: underline;
}

.nav-link:focus-visible {
  outline: 2px solid var(--color-red);
  outline-offset: 4px;
}

/* ---------- Home ---------- */

.home {
  position: relative;
  height: 100%;
  min-height: 480px;
  overflow: hidden;
  background: var(--color-home-bg);
  scroll-snap-align: start;
}

/* Fullscreen featured gallery: a button, so click / Enter / tap advances; swipes are handled in script.js */
.home-stage {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  overflow: hidden;
  cursor: pointer;
  touch-action: pan-y;
  transform: scale(calc(1 - var(--p) * var(--photo-shrink)));
  will-change: transform;
}

.home-stage:focus-visible {
  outline: 2px solid var(--color-red);
  outline-offset: -8px;
}

/* Each slide crops around its focus point (set in the image manager) */
.home-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  opacity: 0;
  user-select: none;
}

.home-slide.is-active {
  opacity: 1;
}

.home-slide.is-flipped {
  transform: scaleX(-1);
}

/* Loading: hidden until decoded, then fades in while settling from a slight zoom. Switching between
   loaded slides stays instant; an inactive slide plays this unseen (its opacity stays 0). */
.home-slide.is-loading {
  opacity: 0;
}

.home-slide.is-revealed {
  animation: slide-reveal 1.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}

@keyframes slide-reveal {
  from {
    opacity: 0;
    scale: 1.06;
  }
}

/* While the slide on show is still loading, the empty stage gently pulses */
.home-stage.is-loading {
  animation: stage-pulse 1.6s ease-in-out infinite;
}

@keyframes stage-pulse {
  50% {
    background-color: #efede8;
  }
}

@media (prefers-reduced-motion: reduce) {
  .home-slide.is-revealed,
  .home-stage.is-loading {
    animation: none;
  }
}

.home-nav,
.home-tagline {
  position: absolute;
  left: 50%;
  z-index: 1;
  width: var(--row-width);
  margin: 0;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.home-nav {
  top: var(--row-inset);
}

.home-tagline {
  bottom: var(--row-inset);
  pointer-events: none;
}

.home-tagline-line {
  display: contents;
}

/* Scroll dissolve (values from React Bits Scroll Reveal): --dissolve 0 → 1 is set per word by script.js */
.home-nav .nav-link,
.home-tagline-line > span,
.work-nav .nav-link,
.work-copyright {
  display: inline-block;
  transform-origin: 0% 50%;
  opacity: calc(1 - var(--dissolve, 0));
  filter: blur(calc(var(--dissolve, 0) * 4px));
  rotate: calc(var(--dissolve, 0) * 3deg);
  will-change: opacity, filter;
}

/* Load-in on the home page: same blur/fade/tilt, played forwards. Fill "backwards" only, so once
   it ends the scroll dissolve takes over again. --i (word index) is set by script.js */
.home-nav .nav-link,
.home-tagline-line > span {
  animation: word-in 0.9s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
  animation-delay: calc(0.3s + var(--i, 0) * 0.08s);
}

@keyframes word-in {
  from {
    opacity: 0;
    filter: blur(4px);
    rotate: 3deg;
  }
}

@media (prefers-reduced-motion: reduce) {
  .home-nav .nav-link,
  .home-tagline-line > span {
    animation: none;
  }
}

/* ---------- Logo (fixed; moves between home and work states) ---------- */

.site-logo {
  position: fixed;
  left: 50%;
  top: calc((1 - var(--p)) * 50% + var(--p) * var(--logo-compact-y));
  z-index: 10;
  display: flex;
  align-items: center;
  width: max-content;
  color: inherit;
  text-decoration: none;
  transform:
    translate(-50%, -50%)
    scale(calc(var(--logo-base-scale) + (var(--logo-compact-scale) - var(--logo-base-scale)) * var(--p)));
}

.site-logo:focus-visible {
  outline: 2px solid var(--color-red);
  outline-offset: 8px;
}

.site-logo picture {
  display: block;
  flex-shrink: 0;
}

.site-logo img {
  display: block;
  width: 100%;
  height: 100%;
}

.site-logo-adi {
  width: var(--adi-w);
  height: var(--adi-h);
}

.site-logo-segal-wrap {
  display: flex;
  align-items: center;
  padding-top: var(--segal-offset);
  flex-shrink: 0;
}

.site-logo-segal {
  width: var(--segal-w);
  height: var(--segal-h);
}

/* Scroll-driven: script.js sets grid-template-columns from 1fr (split) to 0fr (closed) */
.site-logo-close {
  display: grid;
  grid-template-columns: 1fr;
  opacity: calc(1 - var(--close) * 1.5);
}

/* Load-in: ADI then Segal rise into place, fading in and coming into focus; the split follows */
.site-logo-adi,
.site-logo-segal {
  animation: logo-in 1.1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.1s backwards;
}

.site-logo-segal {
  animation-delay: 0.22s;
}

@keyframes logo-in {
  from {
    opacity: 0;
    translate: 0 35%;
    filter: blur(6px);
  }
}

/* Load-driven: grows from 0 to its content width, pushing ADI and Segal apart */
.site-logo-split {
  display: grid;
  grid-template-columns: 0fr;
  min-width: 0;
  overflow: hidden;
  animation: logo-split 1.1s cubic-bezier(0.76, 0, 0.24, 1) 0.9s forwards;
}

.site-logo-tags {
  display: block;
  min-width: 0;
  font-size: var(--tags-size);
  line-height: var(--tags-leading);
  letter-spacing: var(--tags-tracking);
  white-space: nowrap;
}

/* The gap lives in the words' padding (not the grid item's) so the 0fr track can reach a true 0 */
.site-logo-tags span {
  display: block;
  padding-inline: var(--split-gap);
  opacity: 0;
  transform: translateY(10px);
  animation: tag-in 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}

.site-logo-tags span:nth-child(1) { animation-delay: 1.55s; }
.site-logo-tags span:nth-child(2) { animation-delay: 1.65s; }
.site-logo-tags span:nth-child(3) { animation-delay: 1.75s; }

@keyframes logo-split {
  to {
    grid-template-columns: 1fr;
  }
}

@keyframes tag-in {
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-logo-split,
  .site-logo-tags span {
    animation-duration: 0.01s;
    animation-delay: 0s;
  }

  .site-logo-adi,
  .site-logo-segal {
    animation: none;
  }
}

/* ---------- Work ---------- */

.work {
  position: relative;
  height: 100%;
  min-height: 480px;
  overflow: hidden;
  background: var(--color-work-bg);
  scroll-snap-align: start;
}

.work-gallery {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  cursor: grab;
}

.work-gallery::-webkit-scrollbar {
  display: none;
}

.work-gallery.is-dragging {
  cursor: grabbing;
  user-select: none;
}

.work-gallery:focus-visible {
  outline: 2px solid var(--color-red);
  outline-offset: -6px;
}

.work-track {
  display: flex;
  align-items: center;
  gap: calc(20 * var(--u));
  margin-inline: auto;
  transition: translate 0.7s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.2s ease;
}

/* Switching category: the strip fades out, is rebuilt, and the new images float in */
.work-track.is-switching {
  opacity: 0;
}

/* --rise (1 → 0) is set by script.js as the work page scrolls in */
.work-item {
  flex-shrink: 0;
  width: calc(var(--w) * var(--u));
  height: calc(var(--h) * var(--u));
  margin: 0;
  overflow: hidden;
  translate: 0 calc(var(--rise, 0) * var(--gallery-rise));
  will-change: translate;
}

.work-item img,
.work-item video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

/* Videos are drawn on their own layer, snapped to whole pixels; in boxes with fractional sizes that
   left a 1px sliver of background at the edge. Bleeding 1px past each side (clipped) covers it. */
.work-item video {
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  margin: -1px;
}

video.home-slide {
  inset: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
}

.work-item--flip img,
.work-item--flip video {
  transform: scaleX(-1);
}

.work-nav {
  position: absolute;
  inset: var(--row-inset) var(--row-side);
  z-index: 1;
  display: grid;
  grid-template-columns: auto auto;
  justify-content: space-between;
  align-content: space-between;
  pointer-events: none;
}

.work-nav .nav-link {
  pointer-events: auto;
}

.work-nav-filter,
.work-nav-contact {
  justify-self: start;
}

.work-nav-instagram,
.work-nav-info {
  justify-self: end;
}

/* ---------- Filter dropdown (desktop; Figma "Frame" 3:2) ---------- */

/* Sits 20px under the Filter row (51 + 24 + 20 = 95 in the Figma frame); 5 options × 34px tall */
.work {
  --filter-top: calc(var(--row-inset) + 44px);
  --filter-height: 170px;
  --filter-gap: 40px;
}

.work-filter {
  position: absolute;
  left: var(--row-side);
  top: var(--filter-top);
  z-index: 2;
  visibility: hidden;
  /* stays visible until the last option has faded out (0.35s + 4 × 40ms) */
  transition: visibility 0s 0.55s;
}

.work.is-filter-open .work-filter {
  visibility: visible;
  transition-delay: 0s;
}

.work-filter-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 31px;
  line-height: 34px;
  letter-spacing: -1.55px;
  white-space: nowrap;
}

.work-filter button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: left;
  text-underline-offset: 5px;
  text-decoration-thickness: 2px;
  cursor: pointer;
  opacity: 0;
  translate: 0 8px;
  transition: opacity 0.35s ease, translate 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
  /* Closing mirrors opening: options leave bottom-first */
  transition-delay: calc((4 - var(--k, 0)) * 40ms);
}

.work.is-filter-open .work-filter button {
  opacity: 1;
  translate: none;
  transition-delay: calc(var(--k, 0) * 40ms);
}

.work-filter button[aria-pressed="true"]::before {
  content: "→";
}

.work-filter button:hover,
.work-filter button:focus-visible {
  text-decoration-line: underline;
}

.work-filter button:focus-visible {
  outline: 2px solid var(--color-red);
  outline-offset: 4px;
}

/* While open: Filter is underlined, the strip drops so its tallest images start --filter-gap below
   the list (the bottom of the strip may crop), the images turn grayscale, and Contact / Info step aside */
.work.is-filter-open .work-nav-filter {
  text-decoration-line: underline;
}

.work.is-filter-open .work-track {
  translate: 0 calc(var(--filter-top) + var(--filter-height) + var(--filter-gap) - (100svh - 825 * var(--u)) / 2);
}

.work-item img,
.work-item video {
  transition: filter 0.6s ease;
}

.work.is-filter-open .work-item :is(img, video) {
  filter: grayscale(1);
}

.work.is-filter-open .work-nav-contact,
.work.is-filter-open .work-nav-instagram,
.work.is-filter-open .work-copyright {
  visibility: hidden;
}

/* Copyright (Figma 7:40): centred on the bottom row, its 24px line level with Contact and Instagram */
.work-copyright,
.work-grid-copyright {
  margin: 0;
  font-size: 12px;
  line-height: 24px;
  letter-spacing: -0.36px;
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
}

.work-copyright {
  position: absolute;
  left: 50%;
  bottom: var(--row-inset);
  z-index: 1;
  translate: -50% 0;
  transform-origin: 50% 50%;
  pointer-events: none;
}

.work-grid-copyright {
  display: none;
}

/* ---------- Info (Figma 9:42): a white card over the gallery, between the header and the copyright.
   Text sizes never change. On smaller screens the card's spacing shrinks first (full design spacing
   at 814px tall and above, tightest at 660px; side padding from 1440px wide down to 768px); on
   shorter screens still, the photo shrinks too (down to 150px tall at 560px); below that it scrolls. ---------- */

.work-info {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: calc(var(--row-inset) + var(--row-leading) + 20px) var(--row-side);
  overflow-y: auto;
  overscroll-behavior: none;
  background: var(--color-work-bg);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0s 0.4s;
}

.work-info:focus {
  outline: none;
}

.work.is-info-open .work-info {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.4s ease;
}

.work-info-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(16px, calc(22.08svh - 129.7px), 50px);
  width: min(1339px, 100%);
  padding:
    clamp(20px, calc(12.99svh - 65.7px), 40px)
    clamp(20px, calc(4.46vw - 14.2px), 50px)
    clamp(34px, calc(42.86svh - 248.9px), 100px);
  background: #fff;
  translate: 0 30px;
  transition: translate 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.work.is-info-open .work-info-card {
  translate: 0 0;
}

.work-info-statement {
  max-width: 958px;
  margin: 0;
  font-size: 32px;
  line-height: 36px;
  letter-spacing: -1.6px;
  text-align: center;
}

/* Photo-booth print: grey mount, thin black edge, both a hair off straight. --photo-h is the
   mount's height (250px in the design); the rest follows it */
.work-info-photo {
  --photo-h: clamp(150px, calc(100svh - 410px), 250px);
  display: grid;
  place-items: center;
  width: calc(var(--photo-h) * 0.80686);
  height: var(--photo-h);
  padding: 2.4px;
  background: #efefef;
}

.work-info-photo-border {
  padding: 1.6px;
  background: #000;
  rotate: -0.3deg;
}

.work-info-photo img {
  display: block;
  width: calc(var(--photo-h) * 0.80686 - 10.529px);
  height: calc(var(--photo-h) - 9.935px);
  object-fit: cover;
  rotate: 0.3deg;
}

.work-info-details {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  width: 100%;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: -0.36px;
  text-transform: uppercase;
  white-space: nowrap;
}

.work-info-details p {
  margin: 0;
}

.work-info-details .nav-link {
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

/* Info stays underlined while its page is open */
.work.is-info-open .work-nav .work-nav-info {
  text-decoration-line: underline;
}

/* While Info shows, the header keeps only Filter / logo / Info (as in the design) */
.work.is-info-open .work-nav-contact,
.work.is-info-open .work-nav-instagram {
  visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .work-info-card {
    translate: none;
  }
}

.work-empty {
  position: absolute;
  top: 50%;
  left: 50%;
  margin: 0;
  translate: -50% -50%;
  font-size: var(--row-size);
  line-height: var(--row-leading);
  letter-spacing: var(--row-tracking);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Phone-only work layouts, their toggle and the red filter screen (see the mobile section) */
.work-single,
.work-grid,
.work-filter-bg,
.work-nav .work-nav-layout {
  display: none;
}

/* ---------- Tablet ---------- */

@media (min-width: 768px) and (max-width: 900px) {
  :root {
    --logo-base-scale: 0.7;
  }
}

/* ---------- Mobile (Figma: iPhone 17 frame, 402×753) ---------- */

@media (max-width: 767px) {
  :root {
    --row-inset: 20px;
    --row-side: 21px;
    --row-size: 18px;
    --row-leading: 24px;
    --row-tracking: -0.9px;

    --adi-w: 133.31px;
    --adi-h: 47.623px;
    --segal-w: 134.256px;
    --segal-h: 51.993px;
    --segal-offset: 14.007px;
    --split-gap: 9.429px;
    --tags-size: 13px;
    --tags-leading: 13.2px;
    --tags-tracking: -0.65px;

    /* Compact logo on the phone work page (Figma: 101.35 × 25), centred on the Filter / icon row (15 + 24/2) */
    --logo-compact-scale: 0.37877;
    --logo-compact-y: 27px;

    /* svh (toolbar showing) keeps photo sizes fixed while the browser toolbar shows and hides */
    --u: calc(100svh / 1300);
    --gallery-rise: 25svh;
  }
  /* Four links become two corner pairs: Work/Info on top, Contact/Instagram at the bottom */
  .home-nav {
    inset: var(--row-inset) var(--row-side);
    width: auto;
    transform: none;
    display: grid;
    grid-template-columns: auto auto;
    justify-content: space-between;
    align-content: space-between;
    pointer-events: none;
  }

  .home-nav .nav-link {
    pointer-events: auto;
  }

  .home-nav-work { order: 1; justify-self: start; }
  .home-nav-info { order: 2; justify-self: end; }
  .home-nav-contact { order: 3; justify-self: start; }
  .home-nav-instagram { order: 4; justify-self: end; }

  .home-tagline {
    left: var(--row-side);
    top: 71.18%;
    bottom: auto;
    width: auto;
    transform: none;
    display: block;
    line-height: 22px;
  }

  .home-tagline-line {
    display: block;
  }

  /* Page-to-page moves on phones are always the scripted 800ms scroll (script.js), never the browser's
     momentum snap, which varied with how the finger flicked. Only the grid keeps native scrolling. */
  .page,
  .site-logo {
    touch-action: none;
  }

  /* none (not contain): also removes the rubber-band / stretch at the grid's top and bottom */
  .work-grid {
    touch-action: pan-y;
    overscroll-behavior: none;
  }

  /* ----- Work page on phones (Figma: iPhone 17 - 3 / - 2). Header: Filter + layout toggle only ----- */

  .work-nav {
    inset: 15px var(--row-side) auto;
    align-items: center;
  }

  .work-nav .work-nav-instagram,
  .work-nav .work-nav-contact,
  .work-nav .work-nav-info {
    display: none;
  }

  .work-nav .work-nav-layout {
    display: grid;
    justify-self: end;
    width: 17px;
    height: 17px;
  }

  .work-nav-layout img {
    grid-area: 1 / 1;
    display: block;
  }

  .work[data-layout="single"] .icon-single,
  .work[data-layout="grid"] .icon-grid {
    visibility: hidden;
  }

  .work-gallery {
    display: none;
  }

  /* Info on phones: Info takes the layout toggle's place in the header, so it can close again */
  .work.is-info-open .work-nav .work-nav-info {
    display: block;
    justify-self: end;
  }

  .work.is-info-open .work-nav .work-nav-layout {
    display: none;
  }

  .work-info {
    padding: 60px var(--row-side);
    touch-action: none;
  }

  /* Only when the card is taller than the screen may a swipe scroll it. Otherwise pan-y would hand
     the swipe to the page behind it, which then slid on its own and fought the scripted page swipe. */
  .work-info.is-scrollable {
    touch-action: pan-y;
  }

  /* Phones: full spacing at 700px tall and above, tightest at 630px; then the photo shrinks */
  .work-info-card {
    gap: clamp(16px, calc(20svh - 110px), 30px);
    padding:
      clamp(18px, calc(17.14svh - 90px), 30px)
      20px
      clamp(22px, calc(25.71svh - 140px), 40px);
  }

  .work-info-photo {
    --photo-h: clamp(150px, calc(100svh - 380px), 250px);
  }

  .work-info-statement {
    font-size: 20px;
    line-height: 24px;
    letter-spacing: -1px;
  }

  .work-info-details {
    font-size: 11px;
    line-height: 15px;
    letter-spacing: -0.33px;
  }

  /* ----- Filter on phones (Figma: iPhone 17 - 4): a red screen wipes down, then the options fade in;
     closing reverses it (options out bottom-first, then the red wipes back up) ----- */
  .work-filter-bg {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 2;
    background: var(--color-red);
    clip-path: inset(0 0 100% 0);
    transition: clip-path 0.5s cubic-bezier(0.76, 0, 0.24, 1) 0.25s;
  }

  .work.is-filter-open .work-filter-bg {
    clip-path: inset(0);
    transition-delay: 0s;
  }

  .work-filter {
    left: var(--row-side);
    top: 71px;
    z-index: 3;
    color: #fff;
    transition: visibility 0s 0.8s;
  }

  .work-filter-list {
    line-height: 38px;
  }

  .work.is-filter-open .work-filter button {
    transition-delay: calc(0.25s + var(--k, 0) * 40ms);
  }

  .work-nav {
    z-index: 4;
    transition: color 0.3s ease;
  }

  .work.is-filter-open .work-nav {
    color: #fff;
  }

  /* Underlined only while the dropdown is shown (phones keep :hover after a tap, so override it) */
  .work-nav .work-nav-filter {
    text-decoration-line: none;
  }

  .work.is-filter-open .work-nav .work-nav-filter {
    text-decoration-line: underline;
  }

  /* The red logo and icon turn white over the red screen */
  .work-nav-layout img,
  .site-logo img {
    transition: filter 0.3s ease;
  }

  .work.is-filter-open .work-nav-layout img,
  .is-filter-open .site-logo img {
    filter: brightness(0) invert(1);
  }

  /* Copyright: at the bottom of the one-at-a-time view (15px, like the header's top inset);
     in the grid it's the last row instead */
  .work-copyright {
    bottom: 15px;
  }

  /* (the grid shows its own copy at the end of its scroll; the Info page keeps this one) */
  .work[data-layout="grid"]:not(.is-info-open) .work-copyright {
    visibility: hidden;
  }

  .work-grid-copyright {
    display: block;
    grid-column: 1 / -1;
  }

  /* Empty category: no frame, just the "Nothing in … yet" note */
  .work.is-empty .work-single-frame {
    visibility: hidden;
  }

  /* Default layout: the current image centred (2:3, 360 × 540 on the 402 × 753 frame),
     the previous one fullscreen and grayscale behind it */
  /* Both layouts stay laid out; switching crossfades them (the inactive one fades out and is hidden) */
  .work-single,
  .work-grid {
    transition: opacity 0.45s ease, visibility 0s 0.45s;
  }

  .work[data-layout="single"] .work-single,
  .work[data-layout="grid"] .work-grid {
    transition: opacity 0.45s ease, visibility 0s;
  }

  .work[data-layout="grid"] .work-single,
  .work[data-layout="single"] .work-grid {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }

  .work-single {
    display: block;
  }

  /* Vertical swipes here change the image (script.js), so the browser mustn't scroll the page */
  .work-single {
    position: absolute;
    inset: 0;
    overflow: hidden;
    touch-action: none;
  }

  .work-single-bg > *,
  .work-single-frame > * {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    user-select: none;
    transition: opacity 0.6s ease, scale 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  /* The frame is usually a fractional size on real phones; the image layer snaps to whole pixels,
     which left a hairline of the frame's background around dark-edged photos. Bleed 1px (clipped). */
  .work-single-frame > * {
    inset: -1px;
    width: calc(100% + 2px);
    height: calc(100% + 2px);
  }

  .work-single-bg > * {
    filter: grayscale(1);
  }

  .work-single-frame {
    --frame-w: min(calc(100vw - 42px), 47.81svh);
    position: absolute;
    left: 50%;
    top: calc(50% + 0.5px);
    width: var(--frame-w);
    height: calc(var(--frame-w) * 1.5);
    margin: 0;
    padding: 0;
    border: 0;
    background: var(--color-work-bg);
    overflow: hidden;
    cursor: pointer;
    translate: -50% calc(-50% + var(--rise, 0) * var(--gallery-rise));
    transition: width 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), height 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  /* Horizontal images: full width, at their own proportions (--ar, set by script.js), uncropped */
  .work-single-frame.is-landscape {
    --frame-w: calc(100vw - 42px);
    height: calc(var(--frame-w) / var(--ar));
  }

  .work-single-frame:focus-visible {
    outline: 2px solid var(--color-red);
    outline-offset: 4px;
  }

  .work-single-bg > .is-entering,
  .work-single-frame > .is-entering {
    opacity: 0;
  }

  .work-single-frame > .is-entering {
    scale: 1.04;
  }

  .work-single .is-flipped {
    transform: scaleX(-1);
  }

  /* Grid layout: two columns of 2:3 crops, scrolling under a clear header band */
  .work-grid {
    display: grid;
  }

  /* Entering the grid: cells fade up one after another (--n is the cell's order, capped) */
  .work[data-layout="grid"] .work-grid-item {
    animation: grid-cell-in 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) backwards;
    animation-delay: calc(var(--n, 0) * 35ms);
  }

  @keyframes grid-cell-in {
    from {
      opacity: 0;
      translate: 0 16px;
    }
  }

  .work-grid {
    position: absolute;
    top: 55px;
    left: 0;
    right: 0;
    bottom: 0;
    grid-template-columns: 1fr 1fr;
    /* dense: a portrait after a horizontal image fills the gap beside the one before it */
    grid-auto-flow: row dense;
    align-content: start;
    column-gap: 14.4px;
    row-gap: 20.2px;
    /* 15px at the bottom: the copyright that ends the scroll sits where it does in the other views */
    padding: 0 20px 15px;
    overflow-y: auto;
  }

  /* 2:3 via bottom padding: grid rows don't size from aspect-ratio on buttons in every browser */
  .work-grid-item {
    position: relative;
    height: 0;
    margin: 0;
    padding: 0 0 150%;
    border: 0;
    background: #efede8;
    overflow: hidden;
    cursor: pointer;
  }

  /* 1px bleed (clipped by the cell), for the same hairline reason as the single-image frame */
  .work-grid-item > * {
    position: absolute;
    inset: -1px;
    width: calc(100% + 2px);
    height: calc(100% + 2px);
    display: block;
    object-fit: cover;
  }

  /* Horizontal images span both columns at their own proportions (--ar, set by script.js) */
  .work-grid-item.is-landscape {
    grid-column: 1 / -1;
    padding-bottom: calc(100% / var(--ar));
  }

  .work-grid-item > .is-flipped {
    transform: scaleX(-1);
  }

  .work-grid-item:focus-visible {
    outline: 2px solid var(--color-red);
    outline-offset: 3px;
  }
}
