/* BurnerPeople.com — photo viewer (viewer.js). Night palette over the same
   Oswald/Barlow pair as the page. Self-contained: everything is scoped under
   .bpv so it can ride along with gallery.css without leaking either way.
   Fonts come from the @font-face rules in gallery.css. */

.bpv {
  --night: #120e0a;
  --night-2: #1c1610;
  --night-ink: #efe4cf;
  --night-muted: #b8a68c;
  --night-rust: #d9703a;
  --rust: #b4551f;
  --rust-deep: #963f13;
  --display: Oswald, sans-serif;
  --text: Barlow, system-ui, sans-serif;

  --bpv-line: rgba(239,228,207,.12);
  --bpv-fill: rgba(255,250,238,.08);
  --bpv-fill-hover: rgba(255,250,238,.16);
  --bpv-ease: cubic-bezier(.22,.68,.28,1);
  /* Set from JS: how tall the bottom bar is, so the dot and the toast clear it. */
  --bpv-bar-bottom: 0px;

  position: fixed;
  inset: 0;
  z-index: 1000;
  font-family: var(--text);
  color: var(--night-ink);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  overscroll-behavior: contain;
  touch-action: none;      /* nothing in the overlay may scroll or zoom the page */
}

.bpv,
.bpv *,
.bpv *::before,
.bpv *::after { box-sizing: border-box; }

.bpv[hidden],
.bpv [hidden] { display: none !important; }

.bpv:focus,
.bpv :focus { outline: none; }
.bpv :focus-visible { outline: 2px solid var(--night-rust); outline-offset: 3px; }

.bpv svg {
  display: block;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

/* While a viewer is open the page behind it must not scroll. The overlay
   itself has touch-action:none, so touches never reach the page either. */
html.bpv-open { overflow: hidden; padding-right: var(--bpv-sbw, 0px); }
html.bpv-open body { overscroll-behavior: none; }

/* ── backdrop ─────────────────────────────────────────────────────────── */

.bpv-backdrop {
  position: absolute;
  inset: 0;
  background: var(--night);
  opacity: 0;
  transition: opacity .32s var(--bpv-ease);
}

.bpv.is-in .bpv-backdrop { opacity: 1; }
.bpv.is-out .bpv-backdrop { opacity: 0; transition-duration: .26s; }
.bpv.is-dragging .bpv-backdrop { transition: none; }

/* ── stage ────────────────────────────────────────────────────────────── */

.bpv-stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: none;
}

.bpv-track {
  position: absolute;
  inset: 0;
  will-change: transform;
}

/* The photo owns the viewport edge to edge at every size; the bars float
   over it. fit() in viewer.js does the same arithmetic for the frame box. */
.bpv-slide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.bpv-slide.is-empty { visibility: hidden; }

.bpv-frame {
  position: relative;
  flex: none;
  border-radius: 2px;
  overflow: hidden;
  background: var(--night-2);
  transform-origin: 50% 50%;
}

.bpv-frame.is-anim { transition: transform .28s var(--bpv-ease); }
.bpv-slide.is-current .bpv-frame { will-change: transform; }

.bpv-ph,
.bpv-img,
.bpv-video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  pointer-events: none;
}

.bpv-img {
  opacity: 0;
  transition: opacity .25s ease;
}

.bpv-img.is-ready { opacity: 1; }

.bpv-video {
  background: #000;
  pointer-events: auto;
}

.bpv-slide.is-video .bpv-ph,
.bpv-slide.is-video .bpv-img { display: none; }

/* Click zones: the outer quarters navigate on hover-capable devices. Pure
   cursor affordance — the stage handles the click itself. */
.bpv-zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 25%;
  display: none;
  cursor: pointer;
}

.bpv-zone-prev { left: 0; }
.bpv-zone-next { right: 0; }


/* ── vertical pager (touch) ───────────────────────────────────── */

/* .is-vertical is set by viewer.js from its own (hover: hover) and
   (pointer: fine) query — the same one the desktop rules above use — so the
   script and this stylesheet can never disagree about the mode. On a phone or
   tablet the track becomes a scroll-snap pager: flick up for the next photo,
   down for the previous, with the browser's own fling and rubber band. */

.bpv.is-vertical,
.bpv.is-vertical .bpv-stage,
.bpv.is-vertical .bpv-slide { touch-action: pan-y; }

.bpv.is-vertical .bpv-track {
  overflow-x: hidden;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scroll-behavior: auto;          /* the silent re-centre must never animate */
  overscroll-behavior: contain;
  overflow-anchor: none;          /* viewer.js owns scrollTop, not the browser */
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  touch-action: pan-y;
  will-change: auto;
}

.bpv.is-vertical .bpv-track::-webkit-scrollbar { width: 0; height: 0; }

.bpv.is-vertical .bpv-slide {
  position: relative;
  inset: auto;
  width: 100%;
  height: 100dvh;                 /* engines without dvh take the measured px below */
  height: var(--bpv-vh, 100%);
  scroll-snap-align: center;
  scroll-snap-stop: always;       /* three slides in the DOM: never skip one */
  overflow-anchor: none;
}

/* There is nothing to page to past the first and last photo, so the empty edge
   slide leaves the flow and the scroller has no snap point beyond the set. */
.bpv.is-vertical .bpv-slide.is-empty { display: none; }

/* Zoomed, or mid-pinch, the pan logic keeps the photo under the finger — the
   scroller must not steal the drag. overflow: hidden is still a scroll
   container, so scrollTop survives until paging resumes at 1×. */
.bpv.is-vertical.is-zoomed,
.bpv.is-vertical.is-pinching,
.bpv.is-vertical.is-zoomed .bpv-stage,
.bpv.is-vertical.is-pinching .bpv-stage,
.bpv.is-vertical.is-zoomed .bpv-slide,
.bpv.is-vertical.is-pinching .bpv-slide { touch-action: none; }

.bpv.is-vertical.is-zoomed .bpv-track,
.bpv.is-vertical.is-pinching .bpv-track { overflow: hidden; touch-action: none; }

/* The bars float over the pager, outside the scroller, so on touch every
   pixel of them was a place a flick could not start — a dead band of a fifth
   of a portrait screen, and about half a landscape one once the nudge strip
   shows. They are transparent to the finger now; only the real controls
   inside them take it back. Desktop keeps its solid bars: hovering one is
   what holds the auto-hiding chrome open. */
.bpv.is-vertical .bpv-top,
.bpv.is-vertical .bpv-bottom,
.bpv.is-vertical .bpv-nudge { pointer-events: none; }

.bpv.is-vertical .bpv-counter,
.bpv.is-vertical .bpv-close,
.bpv.is-vertical .bpv-nudge-body a,
.bpv.is-vertical .bpv-nudge-x,
.bpv.is-vertical .bpv-actions,
.bpv.is-vertical .bpv-menu { pointer-events: auto; }

/* The native video controls need the finger more than the pager does — but
   only where they actually are. Everywhere else on the video a vertical flick
   still pages, while a horizontal drag (the scrubber) stays with the video. */
.bpv.is-vertical .bpv-video { touch-action: pan-y; }
.bpv.is-vertical .bpv-video::-webkit-media-controls-panel,
.bpv.is-vertical .bpv-video::-webkit-media-controls-enclosure { touch-action: none; }

/* The shared element that flies between the grid tile and the stage. */
.bpv-ghost {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2;
  max-width: none;
  object-fit: cover;
  border-radius: 2px;
  transform-origin: 0 0;
  will-change: transform;
  pointer-events: none;
  background: var(--night-2);
}

/* Loading dot: appears only when the big image takes its time. */
.bpv-load {
  position: absolute;
  right: calc(20px + env(safe-area-inset-right, 0px));
  bottom: calc(var(--bpv-bar-bottom) + 14px);
  z-index: 4;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--night-rust);
  box-shadow: 0 0 0 4px rgba(217,112,58,.18);
  animation: bpvPulse 1.1s ease-in-out infinite;
}

@keyframes bpvPulse {
  0%, 100% { transform: scale(1);    opacity: .95; box-shadow: 0 0 0 4px rgba(217,112,58,.18); }
  50%      { transform: scale(1.12); opacity: .55; box-shadow: 0 0 0 9px rgba(217,112,58,.04); }
}

/* ── buttons ──────────────────────────────────────────────────────────── */

.bpv-btn {
  appearance: none;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--night-ink);
  cursor: pointer;
  transition: background .18s;
}

.bpv-btn:hover { background: var(--bpv-fill); }

/* Prev / next — desktop only, revealed with the chrome. */
.bpv-arrow {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: none;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-top: -28px;
  padding: 0;
  border: 1px solid var(--bpv-line);
  border-radius: 50%;
  background: var(--bpv-fill);
  color: var(--night-ink);
  cursor: pointer;
  opacity: 0;
  transition: opacity .2s ease, background .18s;
}

.bpv-arrow svg { width: 24px; height: 24px; }
.bpv-arrow-prev { left: 22px; }
.bpv-arrow-next { right: 22px; }
.bpv-arrow:hover { background: var(--bpv-fill-hover); }
.bpv-arrow:disabled { opacity: 0 !important; pointer-events: none; }

@media (hover: hover) and (pointer: fine) {
  .bpv-arrow { display: inline-flex; }
  /* The outer quarters page, in fullscreen as anywhere else. Nothing here
     zooms: a mouse cannot, so there is no zoomed state to dress for and no
     grab cursor to offer. is-zoomed only ever happens on the touch pager. */
  .bpv:not(.is-video) .bpv-zone { display: block; }
  .bpv.is-in:not(.is-chrome-hidden) .bpv-arrow { opacity: 1; }
  .bpv.is-chrome-hidden .bpv-stage { cursor: none; }
}

/* ── top bar ──────────────────────────────────────────────────────────── */

.bpv-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 14px;
  padding:
    calc(2px + env(safe-area-inset-top, 0px))
    calc(6px + env(safe-area-inset-right, 0px))
    2px
    calc(16px + env(safe-area-inset-left, 0px));
  /* Short and dark at the very edge: enough to read the counter over a bright
     sky, gone before it starts veiling the photo. */
  background: linear-gradient(rgba(18,14,10,.68), rgba(18,14,10,0));
  transition: opacity .25s ease;
}

.bpv-counter {
  flex: none;
  font-family: var(--display);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: .24em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--night-ink);
}

.bpv-meta {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: 11.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--night-muted);
}

/* ── bottom bar ───────────────────────────────────────────────────────── */

.bpv-bottom {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding:
    24px
    calc(16px + env(safe-area-inset-right, 0px))
    calc(8px + env(safe-area-inset-bottom, 0px))
    calc(16px + env(safe-area-inset-left, 0px));
  background: linear-gradient(rgba(18,14,10,0), rgba(18,14,10,.74) 58%);
  transition: opacity .25s ease;
}

.bpv-actions {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 8px;
  max-width: 100%;
}

.bpv-act {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--bpv-line);
  border-radius: 2px;
  background: var(--bpv-fill);
  color: var(--night-ink);
  font-family: var(--display);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: background .18s, border-color .18s, color .18s;
}

.bpv-act:hover { background: var(--bpv-fill-hover); }

.bpv-act.is-on { background: var(--rust); border-color: var(--rust); color: #fff6e6; }
.bpv-act.is-on:hover { background: var(--rust-deep); border-color: var(--rust-deep); }

.bpv-act-select .bpv-ico-on { display: none; }
.bpv-act-select.is-on .bpv-ico-off { display: none; }
.bpv-act-select.is-on .bpv-ico-on { display: block; }

/* Selection tally. It rides on the icon's corner, out of flow, so the action
   row keeps the same width whether the count is 0, 7 or 99+. */
.bpv-act-ico {
  position: relative;
  flex: none;
  display: inline-flex;
}

.bpv-act-count {
  position: absolute;
  top: -8px;
  right: -9px;
  min-width: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--rust);
  color: #fff6e6;
  font-family: var(--display);
  font-weight: 500;
  font-size: 10px;
  line-height: 15px;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  text-align: center;
  /* A night ring: on a phone the buttons are bare, so this is what keeps the
     pill off a bright sky. */
  box-shadow: 0 0 0 1.5px rgba(18,14,10,.55);
  pointer-events: none;
}

/* On the current photo the button itself turns rust — flip the pill so it
   doesn't sink into it. */
.bpv-act-select.is-on .bpv-act-count {
  background: #fff6e6;
  color: var(--rust-deep);
  box-shadow: none;
}

/* One fullscreen button, two icons: whichever way it is about to go. The
   button carries .is-on like Select does, so the row shows the state. */
.bpv-act-fs .bpv-ico-fs-out { display: none; }
.bpv-act-fs.is-on .bpv-ico-fs-in { display: none; }
.bpv-act-fs.is-on .bpv-ico-fs-out { display: block; }

/* More ⋯ menu */
.bpv-more { position: relative; display: inline-flex; }

.bpv-menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  z-index: 5;
  min-width: 250px;
  padding: 6px;
  border: 1px solid var(--bpv-line);
  border-radius: 2px;
  background: var(--night-2);
  box-shadow: 0 18px 40px -18px rgba(0,0,0,.85);
  animation: bpvMenuIn .16s ease-out both;
}

@keyframes bpvMenuIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.bpv-menu-item {
  appearance: none;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 2px;
  background: transparent;
  color: var(--night-ink);
  font-family: var(--text);
  font-size: 15px;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.bpv-menu-item:hover,
.bpv-menu-item:focus-visible { background: var(--bpv-fill); color: var(--night-ink); }
.bpv-menu-item svg { flex: none; color: var(--night-muted); }

/* Nudge strip: "Looking for yourself?" */
.bpv-nudge {
  display: flex;
  align-items: center;
  gap: 4px 12px;
  max-width: 100%;
  padding: 4px 4px 4px 14px;
  border: 1px solid var(--bpv-line);
  border-radius: 2px;
  background: var(--bpv-fill);
}

.bpv-nudge-body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  min-width: 0;
  font-family: var(--display);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--night-muted);
}

.bpv-nudge-body a {
  color: var(--night-rust);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size .32s var(--bpv-ease);
  padding-bottom: 1px;
}

.bpv-nudge-body a:hover,
.bpv-nudge-body a:focus-visible { background-size: 100% 1px; }

/* ── toast ────────────────────────────────────────────────────────────── */

.bpv-toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--bpv-bar-bottom) + 18px);
  z-index: 6;
  padding: 12px 18px;
  border: 1px solid var(--bpv-line);
  border-radius: 2px;
  background: var(--night-2);
  color: var(--night-ink);
  font-family: var(--display);
  font-weight: 500;
  font-size: 11.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, 8px);
  pointer-events: none;
  transition: opacity .2s ease, transform .2s var(--bpv-ease);
}

.bpv-toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* Screen-reader only text. */
.bpv-sr {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ── chrome states ────────────────────────────────────────────────────── */

/* Chrome fades in with the backdrop and out with it. */
.bpv:not(.is-in) .bpv-top,
.bpv:not(.is-in) .bpv-bottom,
.bpv:not(.is-in) .bpv-arrow { opacity: 0; pointer-events: none; }

.bpv.is-chrome-hidden .bpv-top,
.bpv.is-chrome-hidden .bpv-bottom,
.bpv.is-chrome-hidden .bpv-arrow,
.bpv.is-dragging-close .bpv-top,
.bpv.is-dragging-close .bpv-bottom,
.bpv.is-dragging-close .bpv-arrow {
  opacity: 0;
  pointer-events: none;
}

/* A new photo arrives with a clean frame: the two bars step aside and the
   next mouse movement brings them back. The arrows are deliberately not part
   of it — whoever is clicking one has to be able to click it again, and it
   must not vanish out from under the cursor. viewer.js only ever sets this on
   a hover-capable pointer: the touch pager has nothing to wake it with. */
.bpv.is-bars-hidden .bpv-top,
.bpv.is-bars-hidden .bpv-bottom {
  opacity: 0;
  pointer-events: none;
}

.bpv.is-dragging-close .bpv-top,
.bpv.is-dragging-close .bpv-bottom { transition-duration: .15s; }

/* ── responsive ───────────────────────────────────────────────────────── */

@media (max-width: 559px) {
  .bpv-top { gap: 10px; padding-left: calc(14px + env(safe-area-inset-left, 0px)); }
  .bpv-counter { font-size: 11.5px; letter-spacing: .18em; }
  .bpv-meta { font-size: 10.5px; letter-spacing: .14em; }
  .bpv-bottom { padding-top: 28px; gap: 8px; }
  .bpv-actions { gap: 2px; }
  .bpv-act {
    flex-direction: column;
    gap: 6px;
    min-width: 70px;
    padding: 8px 8px 7px;
    border-color: transparent;
    background: transparent;
    font-size: 10px;
    letter-spacing: .16em;
  }
  .bpv-act:hover { background: var(--bpv-fill); }
  .bpv-act.is-on { background: var(--rust); border-color: var(--rust); }
  /* Three characters grow leftward from the anchor and swallowed the
     checkbox's top edge; at that width the pill sits further out and tighter.
     One and two digits keep the geometry they already had. */
  .bpv-act-count.is-wide { right: -15px; padding: 0 3px; letter-spacing: 0; }
  .bpv-nudge { padding-left: 12px; }
  .bpv-nudge-body { font-size: 10px; letter-spacing: .16em; }
  .bpv-menu { min-width: 236px; }
}

/* Five labelled buttons will not fit across a phone: the row keeps its words
   down to 420px and goes to icons below that, where the words stay on as the
   accessible name. Only when the fullscreen button is really there — without
   it four labelled buttons still fit, and iOS Safari never gets one. */
@media (max-width: 419px) {
  .bpv.has-fs .bpv-act {
    gap: 0;
    min-width: 52px;
    padding: 8px 6px;
  }

  .bpv.has-fs .bpv-act > span:not(.bpv-act-ico):not(.bpv-sr) {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bpv,
  .bpv *,
  .bpv *::before,
  .bpv *::after {
    will-change: auto !important;
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
