:root {
  color-scheme: dark;
  --bg: #14171c;
  --panel: #1d2128;
  --text: #e8e6e1;
  --muted: #8a8f98;
  --correct: #4caf6d;
  --wrong: #c94c4c;
  --neutral: #d9a441;
  --accent: #e8b34c;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

#hud {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 10px 16px;
  background: var(--panel);
  border-bottom: 1px solid #2c313a;
  flex-wrap: wrap;
}

#hearts-display {
  font-size: 20px;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 4px;
}

.hearts-icon { color: var(--wrong); }
.hearts-max { color: var(--muted); font-size: 14px; }

#scene-title {
  font-size: 15px;
  color: var(--muted);
  flex: 1;
}

#dev-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  color: var(--muted);
}

#dev-controls select, #dev-controls button {
  background: #2a2f38;
  color: var(--text);
  border: 1px solid #3a4049;
  border-radius: 4px;
  padding: 4px 8px;
  font-size: 13px;
}

#dev-controls button { cursor: pointer; }
#dev-controls button:hover { background: #343a45; }

main#stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

#scene-frame {
  position: relative;
  width: 100%;
  max-width: 1100px;
  aspect-ratio: 1376 / 768;
  background: #000;
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 8px 30px rgba(0,0,0,0.5);
}

/* Full screen shows only the playable area: #stage goes full screen (not
   #scene-frame itself, which the browser would stretch to the screen's
   aspect ratio and misalign every fractional hotspot), and the frame is
   letterboxed inside it at its own aspect ratio. */
main#stage:fullscreen {
  padding: 0;
  background: #000;
}
main#stage:fullscreen #scene-frame {
  width: min(100vw, 100vh * 1376 / 768);
  max-width: none;
  border-radius: 0;
  box-shadow: none;
}

/* The frame's buttons, top right: sound, start over, full screen. A hidden
   one (full screen where there's no Fullscreen API) just drops out of the
   row. */
#frame-buttons {
  position: absolute;
  top: 2.5%;
  right: 2%;
  z-index: 9; /* above the game-over dim and scene transitions, so they stay usable */
  display: flex;
  gap: 8px;
}
.frame-btn {
  width: 36px;
  height: 36px;
  padding: 7px;
  border: 0;
  border-radius: 6px;
  background: rgba(10, 12, 16, 0.45);
  color: #fff;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.frame-btn[hidden] { display: none; }
.frame-btn:hover,
.frame-btn:focus-visible { opacity: 1; background: rgba(10, 12, 16, 0.7); }
.frame-btn svg,
.preview-icon svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
#game-over.visible ~ #frame-buttons #start-over-btn { display: none; } /* the restart button is right there */
#sound-btn .icon-sound-off,
#sound-btn.off .icon-sound-on { display: none; }
#sound-btn.off .icon-sound-off { display: block; }

/* The start-over confirmation: the first scene in a picture frame, a full
   row of hearts and the restart icon over it. Tap the picture to start
   over, anywhere else to go back to the game. */
#start-over-confirm {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, background 0.25s ease;
}
#start-over-confirm.visible {
  opacity: 1;
  background: rgba(0, 0, 0, 0.72);
  pointer-events: auto;
}
#start-over-yes {
  position: relative;
  width: 40%;
  aspect-ratio: 1376 / 768;
  padding: 0;
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-radius: 8px;
  overflow: hidden;
  background: #000;
  cursor: pointer;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.7);
  transform: scale(0.94);
  transition: transform 0.25s ease, border-color 0.15s ease;
}
#start-over-confirm.visible #start-over-yes { transform: scale(1); }
#start-over-yes:hover,
#start-over-yes:focus-visible { border-color: rgba(255, 255, 255, 0.9); }
#start-over-preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.preview-hearts {
  position: absolute;
  top: 5%;
  left: 5%;
  right: 5%;
  display: flex;
  gap: 0.5%;
}
.preview-hearts .heart-pip { width: 4%; }
.preview-icon {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 20%;
  aspect-ratio: 1;
  padding: 4%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: rgba(10, 12, 16, 0.5);
  color: #fff;
}
.preview-icon svg { stroke-width: 2.2; }

#fullscreen-btn .icon-exit { display: none; }
main#stage:fullscreen #fullscreen-btn .icon-enter { display: none; }
main#stage:fullscreen #fullscreen-btn .icon-exit { display: block; }

#hearts-row {
  position: absolute;
  top: 3%;
  left: 3%;
  right: 20%;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3%;
  pointer-events: none;
  z-index: 5;
}

.heart-pip {
  width: 2.2%;
  aspect-ratio: 1;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.8));
}

.heart-pip svg { width: 100%; height: 100%; display: block; }
.heart-pip.empty svg path { fill: rgba(255,255,255,0.15); }
.heart-pip.filled svg path { fill: var(--wrong); }

/* Everything that is part of the picture (image, video, effects, hotspots,
   sprites, the win glow): a `roll` effect tilts this layer, while the
   hearts and buttons stay put. */
#scene-content {
  position: absolute;
  inset: 0;
}

#scene-image,
#scene-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
}

/* The looped background video sits over the static image, which doubles as
   its placeholder - hidden until the first frame is actually playing, then
   faded in (the video's first frame is the static image, so the crossfade
   is invisible when it works). */
#scene-video {
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
}
#scene-video.ready { opacity: 1; }

#hotspot-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  /* The <svg> container itself is hit-testable over its whole box by
     default, even where nothing is drawn - which was silently blocking
     pointer events meant for sprite <img>s underneath it. Individual
     .hotspot shapes re-enable pointer-events explicitly below. */
  pointer-events: none;
}

#effects-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Above the hotspot polygons, since sprites are drawn on top of the scene
   (scene 011's leaves partly cover the flint and striker). Like the svg, the
   layer itself lets pointer events through; only the sprites catch them.
   isolation keeps the z-index bumped on each pickup (see spriteZ) inside
   this layer, so a sprite never rises above the glow, hearts or overlays. */
#sprite-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  isolation: isolate;
}

.hotspot-sprite {
  position: absolute;
  pointer-events: auto;
  touch-action: none;
  user-select: none;
  -webkit-user-drag: none;
  cursor: pointer;
  /* The hotspot box is hand-placed against whatever crop the sprite image
     currently is - object-fit: fill (the <img> default) would stretch/
     squash it non-uniformly the moment that crop's aspect ratio doesn't
     exactly match the box's, which it now doesn't after a re-crop. */
  object-fit: contain;
}

.hotspot-sprite.pressed {
  filter: brightness(1.12);
}

.hotspot {
  fill: rgba(255, 255, 255, 0.001);
  stroke: none;
  pointer-events: all;
  cursor: pointer;
}

#hotspot-layer.debug .hotspot {
  fill: rgba(255, 60, 60, 0.18);
  stroke: rgba(255, 90, 90, 0.9);
  stroke-width: 0.3;
}

#hotspot-layer.debug .hotspot.discoverable {
  stroke: rgba(120, 170, 255, 0.9);
  fill: rgba(120, 170, 255, 0.12);
}

/* Pressed feedback only in the debug view: in play, invisible hotspots
   must stay invisible - a light fill (moved along with the drag) outlined
   the hit shape, which gives away where the choices are. */
#hotspot-layer.debug .hotspot.pressed {
  fill: rgba(255, 255, 255, 0.25);
}

/* A hint, when a scene has one: the item's own area glows very dimly,
   slowly breathing - never an outline (see applyNudgeState). */
.hotspot.nudge {
  filter: url(#nudge-glow);
  animation: nudge-glow 4s ease-in-out infinite;
}
@keyframes nudge-glow {
  0%, 100% { fill: rgba(255, 236, 190, 0.001); }
  50% { fill: rgba(255, 236, 190, 0.13); }
}
.hotspot-sprite.nudge { animation: nudge-glow-sprite 4s ease-in-out infinite; }
@keyframes nudge-glow-sprite {
  0%, 100% { filter: drop-shadow(0 0 0 rgba(255, 236, 190, 0)); }
  50% { filter: drop-shadow(0 0 8px rgba(255, 236, 190, 0.35)); }
}

/* Scene completed: a small pulsing chevron (no text) hints that a tap
   anywhere goes on to the next scene. */
#continue-hint {
  position: absolute;
  right: 3%;
  bottom: 5%;
  width: 44px;
  height: 44px;
  padding: 8px;
  border-radius: 50%;
  background: rgba(10, 12, 16, 0.4);
  color: #fff;
  opacity: 0;
  pointer-events: none;
  z-index: 6;
  transition: opacity 0.4s ease;
}
#continue-hint.visible {
  opacity: 1;
  animation: continue-nudge 1.6s ease-in-out 0.4s infinite;
}
#continue-hint svg,
#restart-btn svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@keyframes continue-nudge {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(5px); }
}

/* Out of hearts: fade slowly to near-black, then bring in an image-only
   restart button. Sits above everything in the frame so no hotspot is
   reachable underneath. */
#game-over {
  position: absolute;
  inset: 0;
  z-index: 8;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0);
  pointer-events: none;
  transition: background 2.5s ease;
}
#game-over.visible {
  background: rgba(0, 0, 0, 0.9);
  pointer-events: auto;
}
#restart-btn {
  width: 72px;
  height: 72px;
  padding: 16px;
  border: 2px solid rgba(255, 255, 255, 0.55);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 0.8s ease, transform 0.8s ease, background 0.15s ease;
}
#game-over.visible #restart-btn {
  opacity: 0.85;
  transform: scale(1);
  transition-delay: 2.2s, 2.2s, 0s;
}
#restart-btn:hover,
#restart-btn:focus-visible { opacity: 1; background: rgba(255, 255, 255, 0.14); }

/* Scene-to-scene: a quick dip through black. */
#transition-veil {
  position: absolute;
  inset: 0;
  z-index: 7;
  background: #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}
#transition-veil.visible { opacity: 1; }

#scene-frame.flash-wrong #scene-image,
#scene-frame.flash-wrong #scene-video { filter: brightness(0.75) saturate(1.3) hue-rotate(-8deg); }
#scene-frame #scene-image { transition: filter 0.2s ease; }
#scene-frame #scene-video { transition: filter 0.2s ease, opacity 0.3s ease; }

/* No scale/zoom on correct - per feedback, the glow + sparks alone should
   carry the celebration. A quick near-white punch, then a lingering warm
   glow. */
#correct-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  --glow-x: 50%;
  --glow-y: 55%;
  background: radial-gradient(ellipse at var(--glow-x) var(--glow-y), rgba(255, 250, 235, 0.85) 0%, rgba(255, 214, 130, 0.7) 35%, rgba(255, 214, 130, 0) 68%);
  opacity: 0;
}

#correct-glow.playing {
  animation: correct-glow-fade 1.3s ease-out;
}

/* --glow-strength scales the whole glow: 1 for a scene win, less for smaller
   rewards such as a side quest (see playCorrectCelebration). */
@keyframes correct-glow-fade {
  0% { opacity: 0; }
  8% { opacity: var(--glow-strength, 1); }
  30% { opacity: calc(0.75 * var(--glow-strength, 1)); }
  100% { opacity: 0; }
}

#sparkle-layer {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: visible;
}

.sparkle {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #fff3d6;
  box-shadow: 0 0 14px 5px rgba(255, 223, 140, 0.95);
  opacity: 0;
  animation: sparkle-rise 1.1s ease-out forwards;
}

@keyframes sparkle-rise {
  0% { opacity: 0; transform: translate(0, 0) scale(0.3); }
  12% { opacity: 1; transform: translate(0, 0) scale(1.2); }
  100% { opacity: 0; transform: var(--sparkle-end) scale(0.8); }
}

#debug-panel {
  background: var(--panel);
  border-top: 1px solid #2c313a;
  padding: 8px 16px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: var(--muted);
  max-height: 140px;
  overflow-y: auto;
}

#flags-readout { margin-bottom: 6px; }
#log div { padding: 1px 0; }
#log .entry-wrong { color: var(--wrong); }
#log .entry-correct { color: var(--correct); }
#log .entry-neutral { color: var(--neutral); }

/* ---------- index.html: the playable screen alone ----------
   The frame fills the screen as far as it can while keeping its whole
   height and at least the phone-safe band (the middle 42.25% of its width,
   a 3:4 crop - progress.md decision #5) on screen. A desktop or landscape
   phone sees (nearly) the whole 16:9 scene; a portrait phone sees the
   band, cropped evenly on both sides. --crop is how far each side of the
   frame reaches off screen: the overlays near the frame's edges move in by
   that much so they stay visible. */
body.play {
  --frame-w: min(100vh * 1376 / 768, 100vw / 0.4225);
  --crop: max(0px, (var(--frame-w) - 100vw) / 2);
  height: 100vh;
  min-height: 0;
  overflow: hidden;
  overscroll-behavior: none;
  background: #000;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
@supports (height: 100dvh) {
  /* Mobile browsers' collapsing address bar: size to what's visible now. */
  body.play {
    --frame-w: min(100dvh * 1376 / 768, 100vw / 0.4225);
    height: 100dvh;
  }
}
body.play main#stage {
  padding: 0;
  overflow: hidden;
  background: #000;
}
body.play #scene-frame,
body.play main#stage:fullscreen #scene-frame {
  flex: none;
  width: var(--frame-w);
  max-width: none;
  border-radius: 0;
  box-shadow: none;
}
body.play #hearts-row {
  left: calc(var(--crop) + 3%);
  right: calc(var(--crop) + 3% + 136px); /* clear of the three buttons */
}
body.play #hearts-row .heart-pip { width: calc(var(--frame-w) * 0.017); } /* the frame's size, not the row's */
body.play #continue-hint { right: calc(var(--crop) + 3%); }
body.play #frame-buttons { right: calc(var(--crop) + 2%); }
/* The picture: 60% of the frame's width, but never more than 85% of what's
   visible of it (a portrait phone sees only the middle of the frame). */
body.play #start-over-yes { width: min((var(--frame-w) - 2 * var(--crop)) * 0.85, var(--frame-w) * 0.6); }
