/* ==========================================================================
   EXHIBITIONS — pan-and-zoom slideshow of artworks hung in staged scenes.
   Used full-screen (#/exhibition/:slug) and as the lobby hero.
   ========================================================================== */

/* --- Slideshow (shared) --- */
/* The host element (page stage or lobby hero) provides positioning and size. */
.exs {
  overflow: hidden;
  background: var(--color-void);
}

.exs__layer {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.4s var(--ease-gentle);
}

.exs__layer.is-in {
  opacity: 1;
}

/* Exhibition page: behind the room, fitted to the screen, a blurred and darkened copy of it fills
   the bands above and below (or at the sides) until the camera moves in. */
.exs__backdrop {
  position: absolute;
  inset: -6%;
  width: 112%;
  height: 112%;
  object-fit: cover;
  filter: blur(28px) brightness(0.5) saturate(0.9);
  pointer-events: none;
}

.exs__world {
  position: absolute;
  transform-origin: 0 0;
  will-change: transform;
}

.exs__scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.exs__front {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Set per scene by JS: --cm is one centimetre on the wall in screen pixels; --sdx/--sdy the
   direction the shadow falls; --slen its length and --sblur its softness (cm); --sa/--sca the
   cast and contact shadow strength.
   --f is the frame depth in cm: the contact shadow spreads by it, or the frame ring would hide it.
   The cast shadow is a separate element (.exs__shadow), not a box-shadow: a box-shadow is only
   offset, so it detaches from the frame at the corner facing the light. */
.exs__art {
  position: absolute;
  --f: 0;
  --shadow:
    calc(var(--cm) * 0.5 * var(--sdx)) calc(var(--cm) * 0.5 * var(--sdy)) calc(var(--cm) * 0.8) calc(var(--cm) * var(--f)) rgba(20, 12, 4, var(--sca));
  box-shadow: var(--shadow);
}

/* On the exhibition page and the home hero a piece opens its artwork page. */
.exs--linked .exs__art {
  cursor: pointer;
}

.exs--linked .exs__face {
  transition: filter var(--duration-normal) var(--ease-gentle);
}

.exs--linked .exs__art:hover .exs__face,
.exs--linked .exs__art:focus-visible .exs__face {
  filter: brightness(1.08);
}

.exs--linked .exs__art:focus-visible {
  outline: 1px solid var(--color-text-accent);
  outline-offset: 4px;
}

/* Cast shadow of a piece standing off the wall: the frame outline swept along the light direction
   (polygon set by JS), filled evenly and blurred. The blur sits on the outer element so the
   polygon clip on the inner one doesn't cut it off. */
.exs__shadow {
  position: absolute;
  filter: blur(calc(var(--cm) * var(--sblur) * 0.5));
  pointer-events: none;
}

.exs__shadow > div {
  position: absolute;
  inset: 0;
  background: rgb(25, 15, 5);
}

.exs__face {
  position: absolute;
  inset: 0;
}

/* Composite: the face is masked by the image itself; its cast shadow is an SVG filter traced
   from the panels (sweepFilterSVG in exhibition.js, set inline). */
.exs__art.is-composite {
  box-shadow: none;
}

.exs__filters {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.exs__face[style*="mask-image"] {
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.exs__art.is-composite img {
  box-shadow: none !important;
}

.exs__art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;
}

.exs__art[data-frame="gallery_wrap"] img {
  box-shadow: inset calc(var(--cm) * -0.8 * var(--sdx)) 0 calc(var(--cm) * 0.6) rgba(0, 0, 0, 0.25);
}

.exs__art[data-frame="float"] {
  --f: 2.2;
  box-shadow:
    0 0 0 calc(var(--cm) * 0.8) #0e0d0c,
    0 0 0 calc(var(--cm) * 2.2) #c9a77a,
    var(--shadow);
}

/* Same walnut as the room view's dark float (room.css .frame-float-dark). */
.exs__art[data-frame="float_dark"] {
  --f: 2.2;
  box-shadow:
    0 0 0 calc(var(--cm) * 0.8) #0e0d0c,
    0 0 0 calc(var(--cm) * 2.2) #7a3820,
    var(--shadow);
}

.exs__art[data-frame="float_mid"] {
  --f: 2.2;
  box-shadow:
    0 0 0 calc(var(--cm) * 0.8) #0e0d0c,
    0 0 0 calc(var(--cm) * 2.2) #9f6c45,
    var(--shadow);
}

.exs__art[data-frame="float_white"] {
  --f: 2.2;
  box-shadow:
    0 0 0 calc(var(--cm) * 0.8) #0e0d0c,
    0 0 0 calc(var(--cm) * 2.2) #f4f2ee,
    var(--shadow);
}

.exs__art[data-frame="mat"] {
  --f: 9.5;
  box-shadow:
    0 0 0 calc(var(--cm) * 7) #f2eee5,
    0 0 0 calc(var(--cm) * 7.3) #cbb68c,
    0 0 0 calc(var(--cm) * 9.5) #4a3222,
    var(--shadow);
}

/* Scene light falling on the artwork (see sceneLight in exhibition.js). Blurred so only the broad
   light reaches the painting, not the wall's own texture (board joints, plaster cracks); the layers
   overhang the face by 6 cm (JS shifts their background to match) so the blur doesn't fade at the
   edges, and the face clips them. */
.exs__face {
  overflow: hidden;
}

.exs__light {
  position: absolute;
  inset: calc(var(--cm) * -6);
  background-repeat: no-repeat;
  filter: grayscale(1) brightness(var(--lb, 1.15)) blur(calc(var(--cm) * 2.5));
  mix-blend-mode: multiply;
  opacity: var(--shade-op, 0.55);
  pointer-events: none;
}

/* Sun patch on the wall continuing across the painting (only when the scene has one). */
.exs__sun {
  position: absolute;
  inset: calc(var(--cm) * -6);
  display: none;
  background-repeat: no-repeat;
  filter: grayscale(1) brightness(var(--sun-b, 1)) contrast(var(--sun-c, 1)) sepia(0.6) saturate(1.5) blur(calc(var(--cm) * 0.8));
  mix-blend-mode: screen;
  opacity: 0.25;
  pointer-events: none;
}

.has-sun .exs__sun {
  display: block;
}

/* In a sunny scene the shade side of the wall is much darker: let the painting follow it. */
.has-sun .exs__light {
  --shade-op: 0.8;
}

/* A ceiling spotlight: the painting keeps its own colours where the pool is brightest and falls into
   the dark of the wall below it, as the wall does — so the light reads as falling on it, not behind it.
   Only the shade layer works here (normalised to the pool); no light veil, which washed colours out. */
.has-spot .exs__sun {
  display: none;
}

.has-spot .exs__light {
  --shade-op: 0.75;
}

/* --- Title overlay: the works' title under their bottom-right corner, fading in and out with each
   slide (js places it and runs the fades). No panel: the text sits on the wall with a thin gold line
   under it — light text on a dark wall, dark text when the wall behind is light (Joe, 2026-11-02). */
.exs__title {
  position: absolute;
  z-index: 3;
  left: 0;
  top: 0;
  max-width: min(36rem, calc(100% - 32px));
  text-align: right;
  padding: 2px 0 4px;
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.1vw, 2rem);
  font-weight: 400;
  line-height: 1.15;
  color: #f4f0ea;
  text-decoration: none;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 14px rgba(0, 0, 0, 0.35);
  opacity: 0;
}

/* Its work has slid off the screen during the zoom: the title leaves with it. */
.exs__title {
  transition: filter 0.6s var(--ease-gentle);
}

.exs__title.is-out {
  filter: opacity(0);
  pointer-events: none;
}

.exs__title.is-light {
  color: #1d1a17;
  text-shadow: 0 0 10px rgba(255, 252, 246, 0.6);
}

.exs__title-text {
  display: block;
}

.exs__title:hover .exs__title-text,
.exs__title:focus-visible .exs__title-text {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.exs__title-line {
  display: block;
  height: 1px;
  margin-top: 6px;
  background: var(--color-text-accent);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

.exs__title.is-light .exs__title-line {
  background: #8c6a2c;
  box-shadow: none;
}

/* --- Full-screen page --- */
.exhibition {
  position: fixed;
  inset: 0;
  z-index: var(--z-viewer);
}

.exhibition__stage {
  position: absolute;
  inset: 0;
}

.exhibition__back,
.exhibition__controls button {
  font-family: var(--font-body);
  font-size: var(--font-size-small);
  color: var(--color-text-primary);
  background: rgba(5, 5, 6, 0.6);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  cursor: pointer;
  transition: color var(--duration-normal) var(--ease-gentle);
}

.exhibition__back:hover,
.exhibition__controls button:hover,
.exhibition__back:focus-visible,
.exhibition__controls button:focus-visible {
  color: var(--color-text-accent);
}

.exhibition__back {
  position: absolute;
  top: var(--space-md);
  left: var(--space-md);
  z-index: 2;
  padding: 8px 16px;
}

.exhibition__intro {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(24px, 8vw, 120px);
  text-align: center;
  background: rgba(5, 5, 6, 0.74);
  pointer-events: none;
  transition: opacity 1.6s var(--ease-gentle);
}

.exhibition__intro.is-hidden {
  opacity: 0;
}

.exhibition__eyebrow {
  font-size: var(--font-size-small);
  letter-spacing: var(--letter-spacing-wide);
  text-transform: uppercase;
  color: var(--color-text-accent);
  margin-bottom: 12px;
}

.exhibition__title {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 6vw, 4.5rem);
  font-weight: 300;
  line-height: 1.05;
  color: var(--color-text-primary);
}

.exhibition__text {
  margin-top: 18px;
  max-width: 42ch;
  font-size: var(--font-size-body);
  font-weight: 300;
  line-height: var(--line-height-body);
  color: rgba(232, 228, 223, 0.85);
}

.exhibition__controls {
  position: absolute;
  right: clamp(16px, 4vw, 48px);
  bottom: clamp(24px, 5vh, 48px);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
}

.exhibition__controls button {
  width: 40px;
  height: 40px;
  font-size: 1.1rem;
  line-height: 1;
}

/* Music: dimmed while off, gold while playing. */
.exhibition__music {
  opacity: 0.55;
}

.exhibition__controls .exhibition__music.is-on {
  opacity: 1;
  color: var(--color-text-accent);
  border-color: rgba(201, 185, 154, 0.5);
}

.exhibition__count {
  min-width: 3.5em;
  margin-left: 6px;
  font-size: var(--font-size-small);
  letter-spacing: var(--letter-spacing-wide);
  color: var(--color-text-primary);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.7);
}

@media (max-width: 768px) {
  .exs__title {
    font-size: 1.3rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .exs__layer,
  .exhibition__intro {
    transition-duration: 0.01ms;
  }

  .exs__title {
    opacity: 1;
  }

  .exs__title-line {
    transform: none;
  }
}

/* --- Exhibition cards (home-page strip, #/exhibitions) --- */
.exc-row {
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  padding-bottom: 6px;
  scroll-snap-type: x mandatory;
}

.exc-row--grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  overflow: visible;
}

.exc {
  flex: 0 0 min(360px, 82vw);
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--color-text-primary);
  text-decoration: none;
  scroll-snap-align: start;
}

.exc__still {
  position: relative;
  display: block;
  width: 100%;
  overflow: hidden;
  border-radius: 2px;
  background: var(--color-surface);
  margin-bottom: 8px;
}

.exc__scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-gentle);
}

.exc__art {
  position: absolute;
  object-fit: fill;
  box-shadow: 1px 2px 4px rgba(20, 12, 4, 0.45);
}

.exc__art.is-composite {
  box-shadow: none;
  filter: drop-shadow(1px 2px 2px rgba(20, 12, 4, 0.45));
}

.exc:hover .exc__scene,
.exc:focus-visible .exc__scene {
  transform: scale(1.02);
}

.exc__eyebrow {
  font-size: 11px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--color-text-accent);
}

.exc__title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 400;
}

.exc__meta {
  font-size: 13px;
  color: rgba(232, 228, 223, 0.65);
}

/* --- #/exhibitions page --- */
.exlist {
  min-height: 100vh;
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--space-md) clamp(16px, 4vw, 48px) var(--space-lg);
}

.exlist__back {
  font-size: var(--font-size-small);
  color: var(--color-text-accent);
  text-decoration: none;
}

.exlist__title {
  margin: var(--space-sm) 0 var(--space-md);
  font-family: var(--font-display);
  font-size: var(--font-size-room-title);
  font-weight: 300;
  letter-spacing: 0.08em;
}
