:root {
  --gap: clamp(4px, .42vw, 10px);
  --radius: clamp(3px, .35vw, 8px);
  --slot-bg: #070707;
}
* { box-sizing: border-box; }
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
}
body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
#wall {
  width: 100vw;
  height: 100vh;
  padding: var(--gap);
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: repeat(8, 1fr);
  gap: var(--gap);
  background: #000;
  transform-origin: center center;
  perspective: 1400px;
}
.slot {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--slot-bg);
  border-radius: var(--radius);
  isolation: isolate;
  transform-origin: center center;
}
.photo-shell {
  position: absolute;
  inset: 0;
  overflow: hidden;
  backface-visibility: hidden;
}
.shell-current { z-index: 1; opacity: 1; }
.shell-next { z-index: 2; opacity: 0; }
.photo-content {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  display: block;
  transform: none !important;
  animation: none !important;
  transition: none !important;
}
.message {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: grid;
  place-content: center;
  text-align: center;
  background: #111;
  color: #eee;
  padding: 2rem;
}
.message p { max-width: 70ch; }
.hidden { display: none !important; }

/* slot effects */
.shell-next.fx-crossfade { animation: shellCrossfade 850ms ease both; }
.shell-next.fx-soft-fade { animation: shellSoftFade 900ms ease both; }
.shell-next.fx-slide-left { animation: shellSlideLeft 900ms cubic-bezier(.2,.82,.2,1) both; }
.shell-next.fx-slide-right { animation: shellSlideRight 900ms cubic-bezier(.2,.82,.2,1) both; }
.shell-next.fx-blur { animation: shellBlur 900ms ease both; }

@keyframes shellCrossfade { from {opacity:0} to {opacity:1} }
@keyframes shellSoftFade { from {opacity:0;filter:brightness(.86)} to {opacity:1;filter:brightness(1)} }
@keyframes shellSlideLeft { from {opacity:0;transform:translateX(7%)} to {opacity:1;transform:translateX(0)} }
@keyframes shellSlideRight { from {opacity:0;transform:translateX(-7%)} to {opacity:1;transform:translateX(0)} }
@keyframes shellBlur { from {opacity:0;filter:blur(12px)} to {opacity:1;filter:blur(0)} }

/* whole-layout effects */
#wall[data-layout-phase="out"],
#wall[data-layout-phase="in"] {
  transition:
    opacity 850ms ease,
    transform 850ms cubic-bezier(.2,.82,.2,1),
    filter 850ms ease;
}

/* Fade zoom */
#wall[data-layout-effect="fadezoom"][data-layout-phase="out"] {
  opacity: 0; transform: scale(.965); filter: blur(3px);
}
#wall[data-layout-effect="fadezoom"][data-layout-phase="in"] {
  opacity: 1; transform: scale(1); filter: blur(0);
}

/* Slide */
#wall[data-layout-effect="slide"][data-layout-phase="out"] {
  opacity: 0; transform: translateX(-9vw) scale(.98);
}
#wall[data-layout-effect="slide"][data-layout-phase="in"] {
  opacity: 1; transform: translateX(0) scale(1);
}

/* Blur */
#wall[data-layout-effect="blur"][data-layout-phase="out"] {
  opacity: .05; transform: scale(.98); filter: blur(18px);
}
#wall[data-layout-effect="blur"][data-layout-phase="in"] {
  opacity: 1; transform: scale(1); filter: blur(0);
}

/* Dim */
#wall[data-layout-effect="dim"][data-layout-phase="out"] {
  opacity: 0; filter: brightness(.25);
}
#wall[data-layout-effect="dim"][data-layout-phase="in"] {
  opacity: 1; filter: brightness(1);
}

/* Curtain */
#wall[data-layout-effect="curtain"][data-layout-phase="out"] {
  opacity: 0; transform: scaleX(.05); filter: brightness(.55);
}
#wall[data-layout-effect="curtain"][data-layout-phase="in"] {
  opacity: 1; transform: scaleX(1); filter: brightness(1);
}

/* Center expand */
#wall[data-layout-effect="center-expand"][data-layout-phase="out"] {
  opacity: 0; transform: scale(.12);
}
#wall[data-layout-effect="center-expand"][data-layout-phase="in"] {
  opacity: 1; transform: scale(1);
}

/* Directional wipe - approximate via clip-path */
#wall[data-layout-effect="wipe"][data-layout-phase="out"] {
  opacity: .2; clip-path: inset(0 100% 0 0);
}
#wall[data-layout-effect="wipe"][data-layout-phase="in"] {
  opacity: 1; clip-path: inset(0 0 0 0);
}

/* Page turn lite */
#wall[data-layout-effect="page-turn"][data-layout-phase="out"] {
  opacity: 0; transform: rotateY(-11deg) translateX(-4vw) scale(.98);
}
#wall[data-layout-effect="page-turn"][data-layout-phase="in"] {
  opacity: 1; transform: rotateY(0) translateX(0) scale(1);
}

/* Mosaic reveal */
#wall[data-layout-effect="mosaic-reveal"] .slot {
  transition:
    opacity 520ms ease var(--tile-delay, 0ms),
    transform 520ms cubic-bezier(.2,.82,.2,1) var(--tile-delay, 0ms);
}
#wall[data-layout-effect="mosaic-reveal"][data-layout-phase="out"] .slot {
  opacity: 0; transform: scale(.78);
}
#wall[data-layout-effect="mosaic-reveal"][data-layout-phase="in"] .slot {
  opacity: 1; transform: scale(1);
}

/* Tile cascade */
#wall[data-layout-effect="tile-cascade"] .slot {
  transition:
    opacity 520ms ease var(--tile-delay, 0ms),
    transform 520ms cubic-bezier(.2,.82,.2,1) var(--tile-delay, 0ms);
}
#wall[data-layout-effect="tile-cascade"][data-layout-phase="out"] .slot {
  opacity: 0; transform: translateY(7vh) scale(.93);
}
#wall[data-layout-effect="tile-cascade"][data-layout-phase="in"] .slot {
  opacity: 1; transform: translateY(0) scale(1);
}
