/*
 * PLAY — gallery mode styling.
 *
 * FORK-OWNED FILE, and a sibling of gallery.js in the same spirit as
 * controls.js: it is not part of the supersplat-viewer bundle and a rebuild of
 * index.js cannot touch it. See handover.md §4d.
 *
 * Linked from index.html after index.css. Every element starts .hidden and is
 * only revealed by initGallery when a gallery manifest is present, so a normal
 * single-scene tour renders exactly as it did before this file existed.
 *
 * All of it lives inside #ui, so ?noui hides it along with everything else.
 */


/* -- Edge nav zones (NavZones.tsx: 20px mobile / 50px desktop) ------------- */
.galleryZone {
  position: absolute;
  top: 0;
  height: 100%;
  width: 20px;
  border: 0;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.9);
  background: transparent;
  transition: background 200ms ease;
  z-index: 30;
}
@media (min-width: 768px) {
  .galleryZone { width: 50px; }
}
#galleryZoneLeft  { left: 0; }
#galleryZoneRight { right: 0; }
.galleryZone > svg {
  display: block;
  opacity: 0;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.8));
  transition: opacity 200ms ease;
  pointer-events: none;
}
#galleryZoneLeft:hover  { background: linear-gradient(to right, rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0)); }
#galleryZoneRight:hover { background: linear-gradient(to left,  rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0)); }
.galleryZone:hover > svg { opacity: 1; }
/* Touch devices cannot hover — keep the chevron faintly visible so the tap
   target stays discoverable (the isTouch branch in NavZones.tsx). */
@media (hover: none) {
  .galleryZone > svg { opacity: 0.45; }
}

/* -- Bottom clearance for the marketing site's project bar ----------------- *
 * When a gallery is opened from the site's project-detail overlay the player
 * runs inside `<iframe class="detail-tour-frame">` and the site draws its own
 * Prev/Next *project* bar in the PARENT document:
 *   .detail-prevnext-bar { position: fixed; bottom: 22px; z-index: 100 }
 * with ~40px capsules, so it owns roughly y = 22px..62px from the viewport
 * bottom on desktop, and ~56px..96px on a phone (see the safe-area note
 * below). Being in the parent document it always paints above this iframe --
 * no z-index here can get under it, the bottom-anchored UI has to move up.
 *
 * The catch on iOS: the safe-area inset belongs to the TOP-LEVEL document, so
 * the site's bar is pushed up by the home indicator (~34px) while
 * env(safe-area-inset-bottom) inside this iframe reads 0. Measured on a real
 * handset the bar's top edge lands near 96px, not the ~62px a desktop browser
 * shows -- #tourNav's 50px is not enough here, it only looks clear on desktop.
 * 120px puts the pill's bottom edge ~24px above the capsules on a phone and
 * still reads as deliberate on desktop, where the gap is simply larger.
 *
 * Applied only when embedded, so a gallery opened solo at /gallery/<slug>/
 * keeps its original spacing exactly.
 *
 * `.embedded` is set on <html> by index.html's head script -- tours need the
 * same signal for the welcome splash, so the detection does not live in
 * gallery.js any more.
 */
#ui { --gallery-bottom-clear: 0px; }
.embedded #ui { --gallery-bottom-clear: 120px; }

/* The bottom stack is the hint line with the pill above it. The hint is the
   bottom-most element, so it carries the clearance and the pill is offset by
   the hint's own height plus the gap -- keeping the two as one block however
   far up the clearance pushes them. */
#ui { --gallery-hint-stack: 34px; }

/* -- Counter pill (bottom-centre glass pill in GalleryPlayer.tsx) ---------- */
#galleryPill {
  position: absolute;
  bottom: calc(max(20px, env(safe-area-inset-bottom)) + var(--gallery-bottom-clear) + var(--gallery-hint-stack));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: var(--pill-radius);
  background: var(--pill-bg);
  -webkit-backdrop-filter: var(--pill-blur);
          backdrop-filter: var(--pill-blur);
  border: var(--pill-border);
  font-family: var(--ui-font);
  font-size: 11px;
  z-index: 20;
}
#galleryName  { color: var(--pill-text); white-space: nowrap; }
#galleryCount { color: rgba(255, 255, 255, 0.3); font-variant-numeric: tabular-nums; }
#galleryPill > button {
  border: 0;
  cursor: pointer;
  background: transparent;
  color: rgba(255, 255, 255, 0.4);
  font-family: var(--ui-font);
  font-size: 10px;
  letter-spacing: 0.03em;
  border-radius: 999px;
  padding: 2px 8px;
  transition: color 150ms ease, background-color 150ms ease;
}
#galleryPill > button:hover {
  color: #fff;
  background-color: rgba(255, 255, 255, 0.1);
}

/* -- Movement hint line (the tour bar's #tourNavHint, under the pill) ------ *
 * Same component and same control-help card as tours; gallery.js wires it,
 * because the bundle's initTourNav returns early when there is no tour.
 * .detail-splash-hint is the site's own class -- uppercase and tracked on its
 * splash, read as sentence case here, exactly as #tourNavHint does it. */
#galleryHint {
  position: absolute;
  bottom: calc(max(20px, env(safe-area-inset-bottom)) + var(--gallery-bottom-clear));
  left: 50%;
  transform: translateX(-50%);
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  background: none;
  border: 0;
  margin: 0;
  padding: 4px 8px;
  cursor: pointer;
  font-family: var(--ui-font);
  text-transform: none;
  letter-spacing: 0;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 8px;
  transition: color 150ms ease;
  z-index: 20;
}
#galleryHint:hover { color: #fff; }
#galleryHint > svg {
  width: 16px;
  height: 16px;
  display: block;
  flex: none;
}
/* Hidden hint → no stack offset, so the pill drops back onto the clearance. */
#ui:not(:has(#galleryHint:not(.hidden))) { --gallery-hint-stack: 0px; }

/* -- ALLE thumbnail grid (ThumbnailGrid.tsx) ------------------------------- */
#galleryGrid {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 24px;
  /* The site's project bar covers the bottom of this overlay too, which would
     put the last row of thumbnails out of reach -- so the grid takes the same
     clearance rather than a smaller one of its own. See the block above. */
  padding-bottom: calc(40px + var(--gallery-bottom-clear));
  background: rgba(8, 8, 8, 0.75);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  z-index: 90;
}
#galleryGridPanel {
  width: 100%;
  max-width: 980px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  padding: 20px;
  border-radius: 16px;
  background: rgba(20, 20, 24, 0.9);
  -webkit-backdrop-filter: blur(20px);
          backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.4);
}
#galleryGridHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  flex-shrink: 0;
}
#galleryGridTitle {
  font-family: var(--ui-font);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.4);
}
#galleryGridClose {
  border: 0;
  cursor: pointer;
  background: transparent;
  color: rgba(255, 255, 255, 0.4);
  font-family: var(--ui-font);
  font-size: 10px;
  border-radius: 999px;
  padding: 2px 8px;
  transition: color 150ms ease, background-color 150ms ease;
}
#galleryGridClose:hover { color: #fff; background-color: rgba(255, 255, 255, 0.1); }
#galleryGridTiles {
  overflow-y: auto;
  display: grid;
  /* Responsive rather than a hard 12 columns: with exactly 12 scenes that made a
     single row, which then stretched to the panel's height and overrode each
     tile's aspect-ratio (a stretched grid item wins over it), giving very tall
     tiles with the thumbnail tiled down them. */
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  align-content: start;
  align-items: start;
  gap: 8px;
}
.galleryTile {
  position: relative;
  aspect-ratio: 96 / 60;
  border-radius: 8px;
  overflow: hidden;
  cursor: pointer;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background-color: rgba(255, 255, 255, 0.06);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  transition: transform 150ms ease, border-color 150ms ease;
}
.galleryTile:hover  { transform: scale(1.04); }
.galleryTile.active { border-color: rgba(255, 255, 255, 0.6); }
.galleryTile > span {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--ui-font);
  font-size: 9px;
  color: rgba(255, 255, 255, 0.4);
}

/* -- Welcome splash (Splashscreen.tsx) ------------------------------------ */
#gallerySplash {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  background: rgba(8, 8, 8, 0.25);
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
  z-index: 100;
}
/* The card is sized BY the image, not the other way round: no padding and no
   fixed width, so there is no frame left over to letterbox or crop into, and
   overflow:hidden makes the rounded corners the only thing that crops.
   Splash graphics are authored at 800px on their long edge -- wide for the
   desktop cut, high for the mobile one -- and are drawn at 1:1, so these caps
   are the authored size rather than a scale target.
   min-width:0 lets the card shrink below the image's intrinsic width on a
   narrow screen; without it a flex item refuses to, and the image's own
   max-width guard below would never engage. */
#gallerySplashCard {
  /* content-box on purpose: the player sets border-box globally, which would
     make the 1px border below eat into these caps -- an 800px image then gets
     max-width:100% of a 798px content box and is scaled to 798, missing 1:1 by
     two pixels. The caps describe the picture; the border sits outside them. */
  box-sizing: content-box;
  max-width: 800px;
  max-height: 800px;
  min-width: 0;
  overflow: hidden;
  border-radius: 16px;
  background: rgba(30, 30, 34, 0.4);
  -webkit-backdrop-filter: blur(28px) saturate(160%);
          backdrop-filter: blur(28px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
#gallerySplashImage {
  display: block;
  /* No percentage sizing: the browser draws the file at its intrinsic size,
     neither up- nor downscaled. */
  width: auto;
  height: auto;
  /* Guards, and only guards. They do nothing at the authored 800px on a screen
     that has room, and scale the image down proportionally when it genuinely
     cannot fit -- a mobile cut wider than a narrow phone, or a short window --
     which beats having the edges cut off by the viewport. */
  max-width: 100%;
  max-height: 100vh;
}

/* -- Starting-view editor (?edit — EditorPanel.tsx) ------------------------ */
#galleryEditor {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 300px;
  display: flex;
  flex-direction: column;
  background: rgba(8, 8, 8, 0.9);
  -webkit-backdrop-filter: blur(14px);
          backdrop-filter: blur(14px);
  border-left: 1px solid rgba(255, 255, 255, 0.07);
  font-family: var(--ui-font);
  /* The fixed sections (pose readout + thumbnail preview) can add up to more
     than the viewport height on a short window; scroll the panel rather than
     squeezing the scene list to nothing and pushing the export button off. */
  overflow-y: auto;
  z-index: 40;
}
#galleryEditor button {
  width: 100%;
  cursor: pointer;
  background: transparent;
  color: rgba(255, 255, 255, 0.6);
  font-family: var(--ui-font);
  font-size: 10px;
  padding: 8px 0;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: color 150ms ease, background-color 150ms ease;
}
#galleryEditor button:hover:not(:disabled) { color: #fff; background-color: rgba(255, 255, 255, 0.08); }
#galleryEditor button:disabled { opacity: 0.3; cursor: not-allowed; }
#galleryEditorHeader {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.galleryEditorDot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: rgba(74, 222, 128, 0.5);
}
.galleryEditorLabel {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 0.15em;
  text-transform: uppercase;
}
#galleryEditorExit {
  margin-left: auto;
  cursor: pointer;
  font-size: 9px;
  color: rgba(255, 255, 255, 0.2);
  text-decoration: none;
}
#galleryEditorExit:hover { color: rgba(255, 255, 255, 0.4); }
#galleryEditorScene,
#galleryEditorThumbs {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
#galleryEditorName {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.6);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.galleryEditorHint {
  font-size: 9px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.25);
  letter-spacing: 0.1em;
}
#galleryEditorIndex,
#galleryEditorThumbCount,
#galleryEditorCaptureCount {
  text-transform: uppercase;
}
#galleryEditorPose {
  font-family: var(--ui-font);
  font-size: 9px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.4);
  padding: 8px;
  border-radius: 6px;
  overflow-x: auto;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.06);
  white-space: pre;
}
#galleryEditorThumbPreview {
  width: 100%;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
#galleryEditorListHeader { flex-shrink: 0; padding: 12px 16px 4px; }
#galleryEditorList {
  flex: 1 1 auto;
  min-height: 120px;
  max-height: 40vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0 12px 12px;
}
.galleryEditorRow {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  padding: 6px 8px;
  border-radius: 6px;
  cursor: pointer;
  background: transparent;
  border: 1px solid transparent;
  font-family: var(--ui-font);
}
.galleryEditorRow:hover  { background: rgba(255, 255, 255, 0.05); }
.galleryEditorRow.active { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.15); }
.galleryEditorRow > .dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.15);
}
.galleryEditorRow > .dot.has { background: rgba(74, 222, 128, 0.8); }
.galleryEditorRow > .num {
  font-size: 9px;
  color: rgba(255, 255, 255, 0.25);
  width: 20px;
  text-align: right;
  flex-shrink: 0;
}
.galleryEditorRow > .label {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.55);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#galleryEditorFooter {
  padding: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#galleryEditorFooter > button { padding: 10px 0; border-radius: 12px; font-size: 12px; }
#galleryEditorFooter > .galleryEditorHint { text-align: center; }

/* -- Hiding the viewer's own chrome --------------------------------------- */
/* Gallery mode ships PLAYMANY's chrome, so the viewer's toolbar, panels and
   branding are hidden. The class goes on the parent deliberately: the engine's
   own showUI() and its inactivity fade keep adding and removing .hidden /
   .faded-out on #controlsWrap, so hiding it from #ui is the only thing that
   reliably survives. Ctrl+Shift+U / ?debug removes the class. */
#ui.galleryChrome > #controlsWrap,
#ui.galleryChrome > #settingsPanel,
#ui.galleryChrome > #infoPanel,
#ui.galleryChrome > #walkHint,
#ui.galleryChrome > #joystickBase,
#ui.galleryChrome > #annotationNav,
#ui.galleryChrome > #tourNav,
#ui.galleryChrome > #viewerBranding {
  display: none !important;
}

/* -- Toast (editor feedback) ---------------------------------------------- */
#galleryToast {
  position: absolute;
  bottom: 20px;
  right: 316px;
  font-family: var(--ui-font);
  font-size: 11px;
  padding: 8px 12px;
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.7);
  background: rgba(20, 20, 20, 0.92);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  z-index: 60;
}

/* -- ?diag HUD ------------------------------------------------------------ */
/* Built by gallery.js only under ?diag, to watch the sort range and bound
   radius while dollying. Never shown otherwise, so it needs no .hidden state. */
#galleryDiag {
  position: absolute;
  top: 12px;
  left: 12px;
  white-space: pre;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  line-height: 1.5;
  padding: 8px 12px;
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.8);
  background: rgba(20, 20, 20, 0.92);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  pointer-events: none;
  z-index: 60;
}
