/* After Hours dome gallery.

   The tiles sit on the inside face of a sphere built from CSS 3D transforms,
   no WebGL. dome.js sets --dome-r, --tw, --th on the wrapper and --ty / --tx on
   each tile, then spins the sphere by writing --rx / --ry.

   Everything here is scoped under .dome-wrap, so if dome.js never runs the
   gallery stays the plain CSS-column masonry defined on the page. */

.dome-wrap {
  position: relative;
  width: 100%;
  height: var(--dome-h, min(92vh, 940px));
  margin-inline: auto;
  perspective: var(--dome-persp, 1100px);
  perspective-origin: 50% 50%;
  touch-action: none; /* we own the drag */
  cursor: grab;
  /* a drag across the sphere would otherwise select the tiles, and the browser
     paints its selection colour over them as a blue wash */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
  /* fade the rim so tiles leave the frame instead of being cut by a hard edge */
  -webkit-mask-image: radial-gradient(
    ellipse 54% 54% at 50% 50%,
    #000 34%,
    rgba(0, 0, 0, 0.97) 48%,
    rgba(0, 0, 0, 0.89) 58%,
    rgba(0, 0, 0, 0.74) 67%,
    rgba(0, 0, 0, 0.55) 75%,
    rgba(0, 0, 0, 0.35) 83%,
    rgba(0, 0, 0, 0.17) 90%,
    rgba(0, 0, 0, 0.05) 96%,
    transparent 100%
  );
  mask-image: radial-gradient(
    ellipse 54% 54% at 50% 50%,
    #000 34%,
    rgba(0, 0, 0, 0.97) 48%,
    rgba(0, 0, 0, 0.89) 58%,
    rgba(0, 0, 0, 0.74) 67%,
    rgba(0, 0, 0, 0.55) 75%,
    rgba(0, 0, 0, 0.35) 83%,
    rgba(0, 0, 0, 0.17) 90%,
    rgba(0, 0, 0, 0.05) 96%,
    transparent 100%
  );
}
.dome-wrap.is-grabbing {
  cursor: grabbing;
}
.dome-wrap ::selection {
  background: transparent;
}
/* while a drag is in flight the tiles must not swallow the pointer, otherwise
   letting go over a tile counts as a click and opens the lightbox */
.dome-wrap.is-dragging .tile {
  pointer-events: none;
}

.dome-sphere {
  position: absolute;
  left: 50%;
  top: 50%;
  transform-style: preserve-3d;
  transform: translateZ(calc(var(--dome-r) * -1)) rotateX(var(--rx, 0deg))
    rotateY(var(--ry, 0deg));
  will-change: transform;
}

.dome-wrap .tile {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(var(--tw) * var(--twk, 1));
  height: var(--th);
  margin-left: calc(var(--tw) * var(--twk, 1) / -2);
  margin-top: calc(var(--th) / -2);
  transform: rotateY(var(--ty)) rotateX(var(--tx)) translateZ(var(--dome-r));
  backface-visibility: hidden;
  border-radius: 16px;
  transition:
    opacity 0.22s linear,
    filter 0.22s linear;
  cursor: pointer;
}
/* A tile is a link wrapping an image, and both are natively draggable. Starting
   a drag on one hands the gesture to the browser, which cancels our pointer
   sequence, so the sphere just would not turn unless the press happened to land
   in a gutter. */
.dome-wrap .tile,
.dome-wrap .tile img {
  -webkit-user-drag: none;
}
.dome-wrap .tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: none;
}
/* Tiles dissolve as they turn away. dome.js writes --e, a 0 to 1 reading of how
   far past the face each tile has turned, and the falloff is a plain calculation
   from it, so the change is continuous instead of stepping between fixed values.
   Only the rim pays for the blur, and it stays light: the reference keeps its
   edge tiles sharp and lets opacity do most of the work. */
.dome-wrap .tile {
  opacity: calc(1 - 0.92 * var(--e, 0));
  filter: blur(calc(var(--e, 0) * 1.6px))
    saturate(calc(1 - 0.4 * var(--e, 0)));
}
.dome-wrap .tile:hover img,
.dome-wrap .tile:focus-visible img {
  transform: none;
}
.dome-wrap .tile::after {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}
.dome-wrap .tile:hover::after,
.dome-wrap .tile:focus-visible::after {
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.55),
    0 18px 50px -12px rgba(0, 0, 0, 0.75);
}
.dome-wrap .tile:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* an echo is a duplicate of a real tile placed half a turn away */
.dome-wrap .dome-echo {
  cursor: pointer;
}

/* the line under the sphere: what it is and how to drive it */
.dome-hint {
  margin-top: clamp(10px, 1.6vw, 18px);
  text-align: center;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--faint);
  transition: opacity 0.5s var(--ease);
}
.dome-wrap.has-moved ~ .dome-hint {
  opacity: 0;
}

@media (max-width: 720px) {
  .dome-wrap {
    height: var(--dome-h, min(72vh, 620px));
  }
}

/* A reader who asks for less motion gets the masonry instead: dome.js bails out
   before building anything. This block only matters if the preference flips
   after the dome is already up. */
@media (prefers-reduced-motion: reduce) {
  .dome-sphere,
  .dome-wrap .tile {
    transition: none;
  }
}
