/* Home page: the "Moments" full-bleed slideshow + thumbnail INDEX overlay.
   Every number below was measured on the live Squarespace (Momentum) site on
   2026-09-07: reference/GROUND_TRUTH_SPEC_2026-09-07.md §1, the probes in
   reference/probes_2026-09-07/ (captions_arrows.json, index_grid.json,
   index_thumbs.json), reference/momentum_rules_extract.css and Momentum's own
   site.js (the index grid is a Squarespace "autocolumns" gallery: columnWidth 225,
   gutter 37 on desktop; winWidth/3 - 20 and gutter 16 at <= 736px).
   Loaded after /assets/css/site.css (shell tokens + the fixed bottom bar).

   --gallery-bar (set on <html> by gallery.js) = the bar's height minus its 1px top
   border: 88px on desktop, 45px on mobile, and taller when the bar wraps its nav
   under the logo on narrow desktops (live: 108px at 1200 wide). The stage and the
   index overlay both follow it, exactly as Momentum's JS does. */

/* The gallery page never scrolls: the stage fills the viewport above the bar. */
html, body { height: 100%; overflow: hidden; background: #000; }

/* ---------- stage ---------- */
#fullscreenBrowser {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  overflow: hidden;
}
.galleryWrapper { height: 100%; width: 100%; }

/* Momentum: .slideshow height = calc(100vh - 88px) (812px at 900), mobile calc(100vh - 45px).
   The wrapper carries the height so the arrows (siblings of .slideshow) center on the stage. */
.slideshowWrapper {
  position: relative;
  width: 100%;
  height: calc(100vh - var(--gallery-bar, 88px));
  height: calc(100dvh - var(--gallery-bar, 88px));
}
.slideshow {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  touch-action: pan-y;          /* horizontal swipes reach our pointer handlers */
  container-type: size;         /* 100cqw / 100cqh = the slide box, for the focal-point crop */
  -webkit-user-select: none;
  user-select: none;
}

/* Slides are 100% x 100% boxes that slide in from the side (Momentum: .24s
   cubic-bezier(.55,.085,.68,.53)). Only the active slide (and, during a move,
   the outgoing one) is visible. gallery.js sets inline transforms for the move. */
.slide {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
  visibility: hidden;
  transform: translate3d(100%, 0, 0);
}
.slide.is-active { visibility: visible; transform: none; }
.slide.is-moving {
  visibility: visible;
  transition: transform .24s cubic-bezier(.55, .085, .68, .53);
}
.slide .imageWrapper { position: absolute; top: 0; left: 0; right: 0; bottom: 0; }

/* Momentum's crop: scale to cover, then
     left = clamp(-(w*fx - W/2), -(w - W), 0),  top likewise with fy
   (the focal point is centred when it can be, else the image pins to an edge).
   object-position percentages resolve to (box - image) * p, i.e. 100% == W - w,
   so the same clamp is expressible in CSS with the box size in cqw/cqh:
     W/2 - w*fx  =  W*(0.5 - fx) + fx*100%
   The plain percentage line is the fallback for browsers without container units. */
.slide img,
.thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: calc(var(--fx, .5) * 100%) calc(var(--fy, .5) * 100%);
  -webkit-user-drag: none;
}
.slide img {
  object-position:
    clamp(100%, calc(100cqw * (0.5 - var(--fx, .5)) + var(--fx, .5) * 100%), 0px)
    clamp(100%, calc(100cqh * (0.5 - var(--fy, .5)) + var(--fy, .5) * 100%), 0px);
}

/* ---------- prev / next arrows (Momentum .nav-projects) ---------- */
/* Live: 40x40 boxes, opacity 0, .guide = opacity 1. The right arrow is the guide on
   load; on desktop gallery.js moves the guide to whichever half the mouse is on
   (Momentum.FullscreenNavigation) and clears it when the mouse leaves the page; on
   touch the guide stays until the first swipe and never comes back (the live site
   behaves the same with touch emulation: right chevron visible until the first move). */
.nav-projects { list-style: none; margin: 0; padding: 0; }
.nav-projects .arrow-wrapper {
  position: absolute;
  top: 50%;
  margin-top: -20px;            /* 40x40 box, vertically centred on the stage (top 386 at 812) */
  width: 40px;
  height: 40px;
  z-index: 900;
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s;
}
/* Momentum positions the box from the bottom at floor(H/2) + header - 20, i.e. its top is
   ceil(H/2) - 20 (364 on a 767px phone stage, not 363.5); round() reproduces that. */
@supports (top: round(up, 1px, 1px)) {
  .nav-projects .arrow-wrapper { top: round(up, calc(50% - 20px), 1px); margin-top: 0; }
}
.nav-projects .arrow-wrapper.left { left: 25px; }
.nav-projects .arrow-wrapper.right { right: 20px; }
.nav-projects .arrow-wrapper.guide { opacity: 1; }
.nav-projects.at-start .arrow-wrapper.left { display: none; }  /* never on slide 0 */
.nav-projects .arrow-wrapper a {
  display: block;
  width: 40px;
  height: 40px;
  color: #fff;
  -webkit-tap-highlight-color: transparent;
}
/* The live glyph (squarespace-ui-font e02c/e02d, 32px box) renders a 14x28 bright core
   at x = wrapper + 10, y = wrapper + 3 with a 1px anti-aliased halo around it; the SVG
   sits in that box and its stroke is allowed to spill (overflow: visible). */
.nav-projects .arrow-wrapper svg {
  position: absolute;
  left: 10px;
  top: 3px;
  width: 14px;
  height: 28px;
  display: block;
  overflow: visible;
}
body.index-open .nav-projects { display: none; }

@media (max-width: 736px) {
  .slideshowWrapper {
    height: calc(100vh - var(--gallery-bar, 45px));
    height: calc(100dvh - var(--gallery-bar, 45px));
  }
  .nav-projects .arrow-wrapper.left { left: 5px; }
  .nav-projects .arrow-wrapper.right { right: 0; }
}

/* ---------- thumbnail INDEX overlay (#indexProjects) ---------- */
/* Momentum leaves an 89px black band at the top (its header height) even with the
   nav at the bottom; the overlay is viewport-tall, the scroll area is 90% of it, and
   the fixed bar covers the last 88px. While the index is open the bar sits at
   top:-1px, so its bottom edge (= --gallery-bar) is where the overlay starts. */
#indexProjects {
  position: absolute;
  top: var(--gallery-bar, 89px);
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #000;
  z-index: 950;                 /* above the slides and arrows (900), below the bar (1000) */
  display: none;
}
body.index-open #indexProjects { display: block; }
#indexProjects .index-projects-wrapper { display: block; height: 100%; }
#indexProjects .projects-wrapper {
  height: 90%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
/* Momentum: .project { padding: 35px } + .project:last-child { padding-bottom: 100px } */
#indexProjects .project {
  overflow: auto;
  padding: 35px 35px 100px;
}
#indexProjects .gallery-description {
  float: left;
  width: 250px;
}
#indexProjects .gallery-description h2 {
  margin: 0;
  font-family: var(--font);
  font-size: 32px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: .32px;
  color: #e2a6a6;
}
#indexProjects .gallery-description p {
  margin: 16px 0;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.7;
  letter-spacing: .32px;
  color: rgba(255, 255, 255, .7);
  white-space: pre-wrap;
}
/* The grid is a Squarespace "autocolumns" gallery, laid out by gallery.js exactly like
   Momentum: columns = floor(gridWidth / 225), 37px gutters, thumb = floor((gridWidth -
   gutters) / columns), the last column absorbs the remainder (1440: 239px thumbs at
   x = 335/611/887/1163, the last one 242 wide, rows every 276px; 1300: 204px thumbs,
   pitch 241). gallery.js writes grid-template-columns / grid-auto-rows inline; the
   4-column line below is only the pre-JS fallback. */
#indexProjects .thumb-grid {
  position: relative;
  margin: 0 0 0 300px;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 37px;
}
#indexProjects .thumb {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;                 /* the grid row (= thumb width) sets the height... */
  aspect-ratio: 1 / 1;          /* ...and this keeps thumbs square if the JS layout never runs */
  overflow: hidden;
  cursor: pointer;
  opacity: 1;
  transition: opacity .2s cubic-bezier(.55, .085, .68, .53);
  container-type: inline-size;
  background: none;
  border: 0;
  padding: 0;
}
#indexProjects .thumb:hover { opacity: .3; }
#indexProjects .thumb img {
  object-position:
    clamp(100%, calc(100cqw * (0.5 - var(--fx, .5)) + var(--fx, .5) * 100%), 0px)
    clamp(100%, calc(100cqw * (0.5 - var(--fy, .5)) + var(--fy, .5) * 100%), 0px);
  opacity: 0;
  transform: scale(.94);
  transition: opacity .3s ease-out, transform .3s ease-out;   /* bloom in as each thumb loads */
}
#indexProjects .thumb img.bloomed { opacity: 1; transform: scale(1); }
#indexProjects .thumb:focus-visible { outline: 1px solid #e382df; outline-offset: 2px; }

@media (max-width: 1024px) {
  #indexProjects .gallery-description { float: none; width: auto; }
  #indexProjects .thumb-grid { margin: 25px 0; padding: 0; }
  #indexProjects .project h2 { margin-top: 0; }
}
@media (max-width: 768px) {
  #indexProjects .thumb-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 736px) {
  #indexProjects { top: var(--gallery-bar, 45px); }   /* mobile bar: 44px + 1px border */
  #indexProjects .project { padding: 15px 15px 100px; }  /* mobile padding rule keeps :last-child's 100px */
  #indexProjects .thumb-grid { gap: 16px; }              /* Momentum mobile gutter */
  #indexProjects .thumb:hover { opacity: 1; }            /* no hover dim on touch */
}
