/* =====================================================================
   BANGBOWBING OS — THE SCENE (ledger item 44, DESIGN-V3 §12)
   The bodega photo is the level. #scene-stage carries the photo's exact
   aspect ratio and is sized to COVER the viewport, so everything inside it
   can be positioned in percent and track the picture forever — that is the
   whole object-fit maths, done once, in CSS.
   Tokens come from os.css (§3). Loaded after os.css.

   Q14b — no graphics: hotspots carry no icon/prop art any more. Each one is
   a camcorder-style VHS text overlay (idle: a small blinking REC dot only)
   and, on hover or keyboard focus, a digital-camera FOCUS BOX — four corner
   brackets and a small readout — snaps onto the object, exactly the same
   for mouse and keyboard (both just toggle .spot.is-hot).
   ===================================================================== */

:root {
  --art-ar: 1600 / 1019;
  /* the rarity ramp the cases already use, restated for the scene glow */
  --rar-common: #b9c1d2;
  --rar-rare: #4aa3ff;
  --rar-epic: #b07bff;
  --rar-legendary: #ffb43d;
  --hud-top: 52px;
  --hud-bottom: 46px;
}

/* --------------------------------------------------------------- stage --- */
#scene {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: #07060d;
  /* the camera never scrolls vertically; the phone pan is horizontal only */
  overscroll-behavior: contain;
}

#scene-stage {
  position: absolute;
  top: 50%;
  left: 50%;
  aspect-ratio: var(--art-ar);
  /* cover: whichever of the two makes the picture fill the viewport wins */
  width: max(100vw, calc(100vh * 1600 / 1019));
  height: max(100vh, calc(100vw * 1019 / 1600));
  --px: 0px;
  --py: 0px;
  transform: translate(-50%, -50%) translate3d(var(--px), var(--py), 0) scale(1.035);
  transform-origin: 50% 50%;
  will-change: transform;
  background: #07060d url("../assets/bodega-1600.jpg") center / 100% 100% no-repeat;
}
/* os/fx.js mounts its canvas in here: same rectangle, so the sweep is pinned
   to the art and its own cover-fit shader degrades to an identity transform */
#scene-stage > canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* exactly ONE grade over the photo, as the reskin note demands */
#scene-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background:
    radial-gradient(118% 96% at 62% 38%,
      rgba(8, 6, 16, 0) 40%, rgba(8, 6, 16, 0.34) 76%, rgba(8, 6, 16, 0.62) 100%);
  transition: background 0.8s var(--ease), filter 0.8s var(--ease);
}

/* a faint scanline weave over the whole stage — the "tape" in VHS. Kept at
   very low opacity so it reads as texture, not noise, and never touches
   contrast on the overlay text (that lives in its own opaque chip below). */
#scene::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: repeating-linear-gradient(180deg,
    rgba(255, 255, 255, 0.02) 0px, rgba(255, 255, 255, 0.02) 1px,
    transparent 1px, transparent 3px);
  mix-blend-mode: overlay;
  opacity: 0.5;
}

/* ---------------------------------------------------------------- night ---
   The 3AM state (os/scene.js nightNow): the lot goes cold and blue, the shop
   window and the signs are the only warm things left. */
body.is-night #scene-stage {
  filter: brightness(0.56) saturate(0.72) hue-rotate(-12deg) contrast(1.06);
}
body.is-night #scene-stage::after {
  background:
    radial-gradient(42% 34% at 88% 34%, rgba(255, 196, 120, 0.26), transparent 70%),
    radial-gradient(26% 22% at 72% 40%, rgba(255, 214, 150, 0.22), transparent 72%),
    radial-gradient(118% 96% at 62% 38%,
      rgba(10, 8, 30, 0.16) 30%, rgba(8, 6, 22, 0.58) 74%, rgba(4, 3, 12, 0.82) 100%),
    linear-gradient(180deg, rgba(24, 22, 74, 0.34), rgba(6, 5, 20, 0.30));
}

/* -------------------------------------------------------------- hotspots --- */
#scene-spots {
  position: absolute;
  inset: 0;
  z-index: 2;
}

.spot {
  position: absolute;
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  outline: none;
  /* the hit area is the object's box; the art inside may overflow it */
  --rar: var(--rar-common);
}
.spot.rar-rare { --rar: var(--rar-rare); }
.spot.rar-epic { --rar: var(--rar-epic); }
.spot.rar-legendary { --rar: var(--rar-legendary); }

/* -------------------------------------------------- the idle REC dot ---
   The whole of the idle decoration (Q14b): a small, dim, blinking dot so the
   object is findable without a pointer, and nothing else — the scene stays
   a photograph until you look at something. */
.spot-rec {
  position: absolute;
  left: 6px;
  top: 6px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--rar);
  box-shadow: 0 0 0 1px rgba(6, 5, 12, 0.7), 0 0 6px color-mix(in srgb, var(--rar) 70%, transparent);
  opacity: 0.6;
  animation: specRecBlink 2.6s steps(1, end) infinite;
  pointer-events: none;
}
@keyframes specRecBlink {
  0%, 45% { opacity: 0.75; }
  50%, 100% { opacity: 0.28; }
}
.spot.is-hot .spot-rec { opacity: 1; animation: none; background: #ff3b3b; }

/* ------------------------------------------------------- the focus box ---
   A digital-camera viewfinder: four corner brackets snap onto the object's
   box on hover OR keyboard focus (:focus-visible AND .is-hot both drive it,
   so touch-tap — which focuses but may not match :focus-visible — still
   shows it). A subtle inward zoom on the bracketed region; none of it exists
   until the object is engaged, so the idle scene stays uncluttered. */
.spot-frame {
  position: absolute;
  inset: -6%;
  pointer-events: none;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 0.16s var(--ease), transform 0.16s var(--ease);
}
.spot.is-hot .spot-frame, .spot:focus-visible .spot-frame {
  opacity: 1;
  transform: scale(1);
}
.spot-corner {
  position: absolute;
  width: 16px;
  height: 16px;
  border: 0 solid var(--rar);
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--rar) 70%, transparent));
}
.spot-corner.tl { left: 0; top: 0; border-width: 2.5px 0 0 2.5px; }
.spot-corner.tr { right: 0; top: 0; border-width: 2.5px 2.5px 0 0; }
.spot-corner.bl { left: 0; bottom: 0; border-width: 0 0 2.5px 2.5px; }
.spot-corner.br { right: 0; bottom: 0; border-width: 0 2.5px 2.5px 0; }

.spot-readout {
  position: absolute;
  left: 0;
  bottom: -20px;
  font-family: var(--font-pixel);
  font-size: 8px;
  letter-spacing: 0.14em;
  color: #eafcff;
  text-shadow: 1px 0 0 rgba(0, 234, 255, 0.55), -1px 0 0 rgba(255, 0, 122, 0.5);
  white-space: nowrap;
}

/* ------------------------------------------------------- the VHS overlay ---
   Monospace pixel caps label with a slight chroma fringe (cyan/magenta text
   shadows), a micro "REC ●" caption line, and the rarity restated as a text
   tag rather than a coloured pill graphic. Dark, near-opaque chip behind the
   text keeps every line >=4.5:1 on any part of the photo (see the contrast
   table in .workflow/scratch/v3-vhs-verify/CONTRAST.md). */
.spot-vhs {
  position: absolute;
  left: 50%;
  top: calc(100% + 14px);
  z-index: 5;
  width: max-content;
  max-width: min(280px, 54vw, calc(100vw - 24px));
  padding: 7px 10px 8px;
  border-radius: 3px;
  text-align: left;
  /* NOTE-2: faint resting state (label + REC dot legible, not hidden) so
     objects are discoverable without a pointer; full detail still gated to
     hover/focus below. Resting-text pair: #fff text on this bg blended at
     0.55 alpha over rgba(6,5,14,0.94) ~= rgb(144,143,147) on rgb(6,5,14),
     contrast ~6.6:1 -- comfortably clears the 4.5:1 floor at rest too. */
  opacity: 0.55;
  visibility: visible;
  /* item 50: --cap-x is a viewport-clamp nudge in px, set at runtime by
     os/scene.js clampTag() from the caption's actual getBoundingClientRect()
     against window — 0 whenever the box already fits, so desktop (which
     never sets it) is untouched. */
  --cap-x: 0px;
  transform: translate(calc(-50% + var(--cap-x)), 4px);
  transition: opacity 0.14s var(--ease), transform 0.14s var(--ease), visibility 0.14s;
  pointer-events: none;
  font-family: var(--font-mono);
  background: rgba(6, 5, 14, 0.94);
  border: 1px solid color-mix(in srgb, var(--rar) 62%, rgba(255, 255, 255, 0.18));
  border-left-width: 2px;
  border-left-color: var(--rar);
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.6);
}
.spot-vhs.above { top: auto; bottom: calc(100% + 14px); }
.spot-vhs.below { top: calc(100% + 10px); }
.spot.is-hot .spot-vhs, .spot:focus-visible .spot-vhs {
  opacity: 1;
  visibility: visible;
  transform: translate(calc(-50% + var(--cap-x)), 0);
}
@media (prefers-reduced-motion: reduce) {
  .spot-vhs { transition: none; }
}
.spot-vhs-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}
.spot-name {
  font-family: var(--font-pixel);
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.1em;
  color: #ffffff;                              /* 20:1+ on the near-opaque chip */
  text-shadow: 1.5px 0 0 rgba(0, 229, 255, 0.55), -1.5px 0 0 rgba(255, 0, 122, 0.5);
}
.spot-rar {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--rar);
  filter: brightness(1.35);                     /* keeps the darker hues (rare blue) legible */
}
.spot-count {
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 3px;
  color: #ffffff;
  background: #b0163a;                          /* white on this is 6.1:1 */
}
.spot-blurb {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.45;
  color: #d7fbe0;                                /* 12.8:1 on the near-opaque chip */
  letter-spacing: 0.01em;
}
.spot-blurb-mark {
  color: #ff5f6b;                                /* the REC dot's colour, ~6.4:1 */
  font-weight: 700;
}
.spot.is-hot .spot-blurb-mark { animation: specRecBlink 1.1s steps(1, end) infinite; }

/* the object under the pointer gets a fractional lift on the photo too */
.spot.is-hot { z-index: 4; }

/* --------------------------------------------------------- phone camera ---
   <760px the stage is taller-fit than the viewport and therefore wider than
   it, and #scene becomes a horizontal scroller. Native overflow keeps
   momentum, rubber-band and screen-reader panning for free. */
@media (max-width: 759px) {
  #scene {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #scene::-webkit-scrollbar { display: none; }
  #scene-stage {
    position: relative;
    top: auto;
    left: auto;
    /* the stage is in normal flow inside the pan scroller here, so it keeps
       NO centring translate — but it does keep the parallax vars, because on
       a handset the gyro is the only parallax input there is (os/scene.js
       onTilt, capped at +-7px/+-5px). The 1.03 scale is the bleed that keeps
       that nudge from exposing the backdrop at the edges. */
    transform: translate3d(var(--px), var(--py), 0) scale(1.03);
    transform-origin: 50% 50%;
    width: calc((100vh - var(--hud-top)) * 1600 / 1019);
    height: calc(100vh - var(--hud-top));
    min-width: 100vw;
  }
  #scene.is-panning { cursor: grabbing; }
  .spot-vhs { max-width: 62vw; padding: 6px 8px 7px; }
  .spot-blurb { font-size: 10.5px; }
  /* touch has no hover: the REC dot is the affordance, so make it easier to see */
  .spot-rec { width: 9px; height: 9px; }
}

/* a coarse pointer never gets :hover — tapping focuses, which shows the tag */
@media (hover: none) {
  .spot-frame { transition-duration: 0.08s; }
}

/* -------------------------------------------------------- reduced motion ---
   A STATIC SCENE (ledger item 47): no parallax offset on either axis, no
   blinking REC dot, no eased focus box or tag — the focus box still shows on
   hover/focus, it just appears instantly with no snap-in animation (item 50).
   os/scene.js never attaches the pointermove or deviceorientation listener
   under this preference, so --px/--py can never change either — this is the
   belt to that braces. */
@media (prefers-reduced-motion: reduce) and (min-width: 760px) {
  #scene-stage { transform: translate(-50%, -50%) scale(1.035); }
}
@media (prefers-reduced-motion: reduce) and (max-width: 759px) {
  #scene-stage { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #scene-stage { will-change: auto; }
  #scene-stage::after { transition: none; }
  .spot-rec { animation: none; opacity: 0.7; }
  .spot-blurb-mark { animation: none; }
  .spot-frame, .spot-vhs { transition: none; transform: none; }
  .spot-frame { transform: none; }
}

/* QUIET HOTSPOTS — only two physical clicks; keep labels short and calm */
.spot-blurb { display: none; }           /* blurbs lived in the HUD too */
.spot-vhs {
  opacity: 0;
  pointer-events: none;
  padding: 4px 8px;
  max-width: 140px;
  border-width: 1px;
  background: rgba(0, 0, 0, 0.55);
}
.spot.is-hot .spot-vhs,
.spot:focus-visible .spot-vhs {
  opacity: 1;
}
.spot-name { font-size: 11px; letter-spacing: 0.12em; }
.spot-frame { opacity: 0.35; }
.spot.is-hot .spot-frame { opacity: 0.9; }
