/* Animal Rescue village map (js/rescue.js), ported from the rescue village
   prototype (_RetentionLoop codex/retention-world-prototype ce35b6d,
   css/village.css). Same look; for the UI layer tool every painted part that
   the prototype drew with ::before/::after is a real element here (lock
   shackle/body, ground shadow, current halo, rescued heart, next-stage dim and
   overscan, stage rail line), and the clue reveal popup is not used (rescues
   are celebrated in the clear flow). Progress is animal shards (GAME_SPEC §4.11). */

.screen-village {
  --v-grass: #86c35f;
  --v-sand: #f3d79c;
  --v-sand-edge: #d6ad62;
  --v-roof: #e0664a;
  --v-ink: #253052;
  --v-gold: #ffc83d;
  --v-card: #fffaf0;
  --v-go: #43a843;
  /* The deep forest tone the map fades into at its ends. */
  --v-shade: #173220;
  --v-shade-rgb: 23, 50, 32;
  background: #1c2440;
  overflow: hidden;
}

/* .screen is a fixed full-screen column; the village sits in its centre. */
#screen-rescue.screen-village {
  align-items: center;
}

/* .village is the screen column; .village-world holds the full-screen map
   (the scroll box) with the title, buttons and panel floating over it. */
.village {
  position: relative;
  width: 100%;
  max-width: 520px;
  height: 100%;
  overflow: hidden;
}

/* Chinese/Japanese: strict punctuation rules (keep-all + anywhere left "。"
   alone on a line, zh 320 tagline); Chinese breaks between characters,
   Japanese between phrases (auto-phrase, "normal" where unsupported). */
.village-world:lang(ja),
.village-world:lang(zh) {
  word-break: normal;
  line-break: strict;
}

.village-world:lang(ja) {
  word-break: auto-phrase;
}

.village-world {
  position: relative;
  word-break: keep-all;
  overflow-wrap: anywhere;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--v-shade);
  color: var(--v-ink);
  -webkit-user-select: none;
  user-select: none;
}

:root {
  /* How far the notch pushes the top row down; the back button already sits at
     max(10px, safe area), and the title and everything under it follow by the same amount. */
  --village-top-shift: max(0px, calc(env(safe-area-inset-top) - 10px));
}

/* Back to World (the prototype was the hub itself, so it had no back button). */
.village-back {
  position: absolute;
  left: 10px;
  top: max(10px, env(safe-area-inset-top));
  z-index: 9;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 2px solid #ffd34e;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--cs-blue-top), var(--cs-blue-bottom));
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 3px 0 var(--cs-blue-edge), 0 4px 10px rgba(0, 0, 0, 0.3);
  cursor: pointer;
}

.village-back-icon {
  width: 22px;
  height: 22px;
  transform: scaleX(-1);
}

.village-back:focus-visible {
  outline: 3px solid var(--v-gold);
  outline-offset: 3px;
}

.village-next-stage {
  /* The next stage's preview comes from the shown stage's data (peek); this is the fallback. */
  --v-stage2-bg: url("../assets/village/bg-stage2-river-forest-v1.webp");
  --stage-overscan: 48px;
  position: absolute;
  inset: 0 0 auto;
  z-index: 0;
  height: 37.7604%;
  background: var(--v-stage2-bg) left top / 100% 100% no-repeat;
  pointer-events: none;
  translate: 0 var(--world-shift, 0px);
}

/* A preview whose lower edge does not meet the stage art fades out instead (stage data peekFade). */
.village-next-stage[data-peek-fade="true"] {
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 70%, transparent 100%);
}

.village-next-stage-dim {
  position: absolute;
  inset: 0;
  background: var(--v-stage2-bg) left top / 100% 100% no-repeat;
  filter: grayscale(.82) brightness(.72);
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(57% - 14px), transparent calc(57% + 14px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, #000 calc(57% - 14px), transparent calc(57% + 14px), transparent 100%);
}

/* Mirrored locked art above the top edge, so a max pull shows more forest. */
.village-next-stage-overscan {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 100%;
  min-height: var(--stage-overscan);
  background: var(--v-stage2-bg) left top / 100% 100% no-repeat;
  transform: scaleY(-1);
  filter: grayscale(.82) brightness(.72);
}

.village-stage-open {
  position: absolute;
  left: 50%;
  bottom: calc(78.5% + 8px);
  z-index: 8;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  transform: translateX(-50%);
  border: 2px solid #dfe6ef;
  border-radius: 999px;
  background: linear-gradient(180deg, #a9b4c4, #7c899b);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.45), 0 3px 0 #5d6878, 0 4px 10px rgba(0, 0, 0, 0.25);
  color: #fff;
  font: inherit;
  font-size: 15px;
  font-weight: 900;
  white-space: nowrap;
  translate: 0 var(--world-shift, 0px);
}

/* ---------- Header ---------- */
.village-header {
  position: relative;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: calc(110px + var(--village-top-shift));
  padding: calc(76px + var(--village-top-shift)) 16px 8px;
  /* Drags and the wheel on the title area move the map underneath. */
  pointer-events: none;
}

.village-stage-title-panel {
  position: absolute;
  left: 50%;
  top: calc(10px + var(--village-top-shift));
  z-index: 7;
  /* The prototype's 300px; on narrow screens it leaves room for the back
     button and the rail instead of a fixed percentage. */
  width: min(300px, calc(100% - 120px));
  padding: 8px 18px 10px;
  transform: translateX(-50%);
  border: 2px solid var(--cs-gold);
  border-radius: 20px;
  background: linear-gradient(180deg, var(--cs-cream), var(--cs-cream-deep));
  box-shadow: inset 0 2px 0 #fff, 0 3px 0 var(--cs-gold-lo), 0 6px 16px rgba(24, 36, 28, .3);
  text-align: center;
  pointer-events: none;
}

.village-title {
  margin: 0;
  color: #fff;
  font-size: clamp(22px, 6vw, 28px);
  font-weight: 900;
  letter-spacing: .01em;
  line-height: 1.1;
}

.village-tagline {
  margin: 2px 0 0;
  color: var(--cs-brown-soft);
  font-size: 13px;
  font-weight: 700;
}

.village-clue-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  min-height: 40px;
  padding: 0 14px 0 10px;
  border: 2px solid var(--cs-gold);
  border-radius: 999px;
  background: linear-gradient(180deg, var(--cs-cream), var(--cs-cream-deep));
  box-shadow: inset 0 2px 0 #fff, 0 3px 0 var(--cs-gold-lo);
  color: var(--cs-brown);
  font-size: 16px;
  font-weight: 800;
  white-space: nowrap;
}

.village-clue-icon {
  display: inline-block;
  width: 22px;
  height: 22px;
  object-fit: contain;
}

/* ---------- Map ----------
   The whole screen scrolls the joined stages. Top and bottom padding are the
   title and panel heights (set by js/rescue.js), so every point can reach the
   visible band; the padding shows the deep shade the art fades into. */
.village-map {
  position: absolute;
  inset: 0;
  z-index: 1;
  box-sizing: border-box;
  padding: var(--village-top-h, 180px) 0 var(--village-bottom-h, 240px);
  background: var(--v-shade);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
  scroll-behavior: smooth;
  /* No scrollbar: the stage rail shows where the map is. */
  scrollbar-width: none;
  cursor: grab;
  --map-stage-h: clamp(500px, 66vh, 680px);
}

.village-map.is-dragging { cursor: grabbing; scroll-behavior: auto; }
.village-map::-webkit-scrollbar { display: none; }

.village-map-stage {
  position: relative;
  width: 100%;
  height: var(--map-stage-h);
  container-type: size;
  overflow: hidden;
  isolation: isolate;
}

.village-map-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--stage-bg) center / 100% 100% no-repeat,
    linear-gradient(180deg, #9fd47a 0%, var(--v-grass) 55%, #78b554 100%);
  transition: filter 180ms ease;
  pointer-events: none;
}

.village-map-stage.is-locked .village-map-backdrop,
.village-map-stage.is-locked .village-scene-art,
.village-map-stage.is-locked .village-pet-art { filter: grayscale(1); }

.village-scene-art,
.village-pet-art { transition: filter 180ms ease; }

/* Join: the upper stage lies over the top of the lower one. Its opaque part
   hides the river cut at the lower art's top edge and its last 6% fades into
   the lower stage's grass, so the two scenes read as one world. */
.village-map-stage + .village-map-stage { margin-top: calc(var(--map-stage-h) * -0.18); }
/* Visible overflow: Clock Tower Hill (and Boat Landing) sits at the upper
   stage's bottom edge and its name label hangs over the join. --stage-layer
   (1, 2, … from the bottom, set by js/rescue.js) keeps every upper stage over
   the one below it when three or more stages are stacked. */
.village-map-stage:not(:last-child) { z-index: var(--stage-layer, 1); overflow: visible; }
.village-map-stage:not(:last-child) .village-map-backdrop {
  -webkit-mask-image: linear-gradient(180deg, #000 94%, transparent);
  mask-image: linear-gradient(180deg, #000 94%, transparent);
}
/* The world's two ends fade into the shade instead of a hard edge. */
.village-map-stage:first-child .village-map-backdrop {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 72px, #000 94%, transparent);
  mask-image: linear-gradient(180deg, transparent 0, #000 72px, #000 94%, transparent);
}
.village-map-stage:last-child .village-map-backdrop {
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 72px), transparent);
  mask-image: linear-gradient(180deg, #000 calc(100% - 72px), transparent);
}
/* Only one open stage: it fades into the shade at both ends. */
.village-map-stage:only-child .village-map-backdrop {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 72px, #000 calc(100% - 72px), transparent);
  mask-image: linear-gradient(180deg, transparent 0, #000 72px, #000 calc(100% - 72px), transparent);
}

/* Fixed shades: the title sits on a deep tone that clears into the map, and
   the map darkens just before it slides under the panel. */
.village-shade {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 2;
  pointer-events: none;
}
.village-shade--top {
  top: 0;
  height: calc(var(--village-top-h, 180px) + 56px);
  background: linear-gradient(180deg, rgba(var(--v-shade-rgb), .72) 0%, rgba(var(--v-shade-rgb), .45) 55%, rgba(var(--v-shade-rgb), 0) 100%);
}
.village-shade--bottom {
  bottom: 0;
  height: calc(var(--village-bottom-h, 240px) + 64px);
  background: linear-gradient(0deg, rgba(var(--v-shade-rgb), .6) calc(100% - 64px), rgba(var(--v-shade-rgb), 0) 100%);
}

.village-area[role="button"] { cursor: pointer; touch-action: manipulation; }
.village-area[role="button"]:focus-visible { outline: 3px solid #fff3b0; outline-offset: 2px; border-radius: 24px; }

.village-path { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

.village-path-marker {
  position: absolute;
  width: clamp(18px, 4.8cqmin, 28px);
  height: auto;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 3px 2px rgba(39, 48, 34, .35));
}

.village-path-marker.is-open { opacity: 1; }

.village-path-marker.is-locked {
  filter: grayscale(1) brightness(.62) drop-shadow(0 3px 2px rgba(39, 48, 34, .32));
}

.village-areas {
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
  padding: 0;
  list-style: none;
}

.village-area {
  --tile: clamp(128px, 42cqmin, 240px);
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--tile);
  height: var(--tile);
  transform: translate(-50%, -50%);
}

/* Each point's place on the map (--x, --y) comes from its data (rescue.points, GAME_SPEC §4.18). */

/* Inside the scene, bottom to top: halo (current only) -> ground shadow -> art. */
.village-scene {
  position: absolute;
  inset: 0;
  isolation: isolate;
}

.village-scene-shadow {
  position: absolute;
  left: 18%;
  right: 18%;
  top: 76%;
  bottom: 8%;
  z-index: 1;
  border-radius: 50%;
  background: #000;
}

.village-scene-art {
  position: relative;
  z-index: 2;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 4px 2px rgba(40, 70, 30, .3));
}

.village-scene-halo {
  position: absolute;
  inset: 5%;
  z-index: 3;
  border-radius: 50%;
  border: 4px dashed #ffd54a;
  filter: drop-shadow(0 2px 1px rgba(93, 66, 7, .45));
  pointer-events: none;
}

.village-area.is-current .village-scene-shadow {
  left: 6%;
  right: 6%;
  top: 68%;
  bottom: 2%;
}

.village-area.is-rescued .village-scene-art { animation: village-bob 1.8s ease-in-out infinite; }

.village-area.is-locked .village-scene-art,
.village-area.is-coming_soon .village-scene-art {
  filter: grayscale(1) saturate(0) brightness(.58);
  opacity: 1;
}

.village-lock {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 5;
  transform: translate(-50%, -50%);
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--v-ink);
  box-shadow: 0 2px 0 rgba(0, 0, 0, .25);
}

.village-lock--pet { top: 34%; }

.village-lock-shackle {
  position: absolute;
  left: 10px;
  top: 6px;
  width: 6px;
  height: 7px;
  border: 2px solid #fff;
  border-bottom: 0;
  border-radius: 5px 5px 0 0;
}

.village-lock-body {
  position: absolute;
  left: 8px;
  top: 13px;
  width: 14px;
  height: 10px;
  border-radius: 2px;
  background: #fff;
}

.village-lock--stage-open {
  position: relative;
  left: auto;
  top: auto;
  flex: 0 0 30px;
  margin: -4px -3px -4px -4px;
  transform: scale(.72);
}

.village-lock--stage-node {
  left: auto;
  top: auto;
  right: -8px;
  bottom: -6px;
  transform: scale(.58);
  transform-origin: right bottom;
}

.village-detective {
  position: absolute;
  left: -4%;
  bottom: 4%;
  height: 48%;
  width: auto;
  filter: drop-shadow(0 4px 2px rgba(20, 40, 20, .35));
}

.village-area-label {
  position: absolute;
  top: calc(100% - 12px);
  left: 50%;
  z-index: 1;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: max-content;
  max-width: 44cqw;
  padding: 3px 10px 4px;
  border: 2px solid var(--cs-gold);
  border-radius: 12px;
  background: var(--cs-cream);
  box-shadow: 0 2px 0 var(--cs-gold-lo);
  color: var(--cs-brown);
  text-align: center;
  line-height: 1.15;
}

.village-area-name { font-size: clamp(13px, 3.9cqmin, 16px); font-weight: 900; }
.village-area-status { font-size: 12px; font-weight: 700; color: var(--cs-brown-soft); }
.village-area.is-rescued .village-area-status { color: #2f7d32; }
.village-area.is-current .village-area-label { border-color: #fff3b0; background: linear-gradient(180deg, #ffe07a, var(--v-gold)); box-shadow: 0 2px 0 #c8912a; }
.village-area.is-current .village-area-status { color: var(--cs-brown); }

/* ---------- Rescue pets ---------- */
.village-pet {
  --pet: clamp(34px, 10cqmin, 52px);
  position: absolute;
  right: -12%;
  bottom: -8%;
  width: var(--pet);
  height: var(--pet);
}

.village-area .village-pet {
  --pet: 48%;
  right: auto;
  bottom: auto;
  z-index: 4;
  left: 26%;
  top: 26%;
}

.village-area .village-pet.is-rescued { animation: village-bob 1.8s ease-in-out infinite; }

.village-area .village-pet.is-current,
.village-area .village-pet.is-locked,
.village-area .village-pet.is-coming_soon {
  filter: brightness(0) invert(1) grayscale(1) drop-shadow(0 2px 0 rgba(37, 48, 82, .35));
}

.village-pet-art {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 3px 0 rgba(0, 0, 0, .18));
}

.village-pet-heart {
  position: absolute;
  right: -8%;
  top: -6%;
  width: 34%;
  height: 34%;
  background: #ff6f8e;
  clip-path: polygon(50% 95%, 5% 45%, 15% 15%, 35% 10%, 50% 28%, 65% 10%, 85% 15%, 95% 45%);
}

/* ---------- Bottom panel ---------- */
.village-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 6;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  align-items: center;
  padding: 16px 16px max(16px, env(safe-area-inset-bottom));
  border: 2px solid var(--cs-gold);
  border-bottom: 0;
  border-radius: 24px 24px 0 0;
  background: linear-gradient(180deg, var(--cs-cream), var(--cs-cream-deep));
  box-shadow: inset 0 2px 0 #fff, 0 -6px 16px rgba(20, 12, 4, .35);
  color: var(--cs-brown);
}

.village-panel-pet {
  position: relative;
  width: 60px;
  height: 60px;
  border: 2px solid var(--cs-gold);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #fffdf5, #f3dfae);
}

.village-panel-pet .village-pet {
  --pet: 46px;
  left: 50%;
  top: 50%;
  right: auto;
  bottom: auto;
  transform: translate(-50%, -50%);
}

.village-panel-text { min-width: 0; }
.village-panel-area { margin: 0; font-size: 13px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: #0a55c9; }
.village-panel-heading { margin: 2px 0 6px; font-size: 19px; font-weight: 900; line-height: 1.2; color: var(--cs-brown); }
.village-panel > .village-panel-heading { grid-column: 1 / -1; text-align: center; }

.village-meter {
  height: 12px;
  border-radius: 999px;
  background: #e8dcc0;
  box-shadow: inset 0 1px 2px rgba(90, 51, 19, .25);
  overflow: hidden;
}

.village-meter-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #ffe07a, var(--v-gold));
  transition: width .6s ease;
}

.village-meter-label { margin: 4px 0 0; font-size: 14px; font-weight: 700; color: var(--cs-brown-soft); }

.village-cta {
  grid-column: 1 / -1;
  min-height: 56px;
  margin-top: 10px;
  padding: 0 20px;
  border: 3px solid var(--ui-gold);
  border-radius: 16px;
  background: linear-gradient(180deg, #b4ff00 0%, #63dd00 42%, #009400 100%);
  box-shadow: 0 5px 0 #006b00, inset 0 2px 0 rgba(255, 255, 255, 0.55);
  color: #fff;
  font: inherit;
  font-size: 21px;
  font-weight: 900;
  cursor: pointer;
}

.village-cta:active { transform: translateY(3px); box-shadow: 0 2px 0 #006b00, inset 0 2px 0 rgba(255, 255, 255, 0.45); }

.village-link {
  grid-column: 1 / -1;
  justify-self: center;
  min-height: 44px;
  min-width: 44px;
  padding: 0 12px;
  border: 0;
  background: none;
  color: var(--cs-brown);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.village-cta:focus-visible,
.village-link:focus-visible {
  outline: 3px solid #0a55c9;
  outline-offset: 3px;
}

/* ---------- Stage navigation ---------- */
/* The rail nodes past the configured stages (4-8 with three stages) are not
   built: a caption at the top of the rail, right above the locked nodes,
   says so. */
.village-stage-soon {
  display: block;
  margin: 0 auto 4px;
  padding: 2px 4px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--cs-blue-top), var(--cs-blue-bottom));
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
}

.village-stage-nav {
  --stage-step: 42px;
  position: fixed;
  right: max(0px, calc((100vw - 520px) / 2));
  top: 50%;
  z-index: 8;
  transform: translateY(-50%);
  padding: 7px 5px 7px 7px;
  border-radius: 18px 0 0 18px;
  background: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .village-map { scroll-behavior: auto; }
  .village-stage-progress,
  .village-map-backdrop,
  .village-scene-art,
  .village-pet-art { transition: none; }
}

.village-stage-viewport {
  width: 36px;
  height: calc(6 * var(--stage-step));
  overflow-x: hidden;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  overscroll-behavior: contain;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
}

.village-stage-viewport.is-dragging { scroll-snap-type: none; }

.village-stage-track {
  position: relative;
  display: flex;
  flex-direction: column;
}

.village-stage-line {
  position: absolute;
  left: 50%;
  top: 21px;
  bottom: 21px;
  z-index: 0;
  width: 2px;
  transform: translateX(-50%);
  background: rgba(255, 255, 255, .55);
  box-shadow: 0 1px 0 rgba(31, 41, 67, .28);
  pointer-events: none;
}

.village-stage-progress {
  position: absolute;
  left: calc(50% - 13px);
  top: 0;
  z-index: 2;
  width: 8px;
  height: 8px;
  transform: translate(-50%, -50%);
  border: 2px solid #fff8d6;
  border-radius: 50%;
  background: #f5b92e;
  box-shadow: 0 0 0 2px rgba(53, 67, 48, .45), 0 1px 3px rgba(0, 0, 0, .35);
  pointer-events: none;
  transition: top 50ms linear;
}

.village-stage-node {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 25.2px;
  height: 25.2px;
  margin: 8.4px auto;
  padding: 0;
  scroll-snap-align: start;
  border: 2px solid rgba(255, 255, 255, .72);
  border-radius: 50%;
  background: linear-gradient(180deg, #7d8799, #4e5667);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 900;
}

.village-stage-node:disabled { pointer-events: none; }

/* An open stage that is not shown: press it to go there (GAME_SPEC §4.18). */
.village-stage-node[data-open="true"] {
  border-color: #eaffd0;
  background: linear-gradient(180deg, #7fd957, #3f9e2c);
  box-shadow: 0 0 0 3px rgba(127, 217, 87, .28), 0 2px 0 #2c7020;
  cursor: pointer;
}

.village-stage-open[data-open="true"] {
  border-color: #fff2a7;
  background: linear-gradient(180deg, #ffd95c, #e8a92c);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 3px 0 #98691c, 0 4px 10px rgba(0, 0, 0, 0.25);
  color: var(--v-ink);
  cursor: pointer;
}

.village-stage-node[aria-current="page"] {
  border-color: #fff2a7;
  background: linear-gradient(180deg, #ffd95c, #e8a92c);
  box-shadow: 0 0 0 3px rgba(255, 211, 75, .28), 0 3px 0 #98691c;
  color: var(--v-ink);
}

/* The always-on cache button would sit on the panel's play button. */

/* ---------- Motion ---------- */
@keyframes village-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-5px); }
}

.village-world.is-locked-nudge .village-lock--stage-open { animation: village-lock-nudge .45s ease-out; }

@keyframes village-lock-nudge {
  0%, 100% { scale: 1; }
  40% { scale: 1.35; }
}

@media (prefers-reduced-motion: reduce) {
  /* An id selector outranks every animated rule above without !important. */
  #screen-rescue * {
    animation: none;
    transition: none;
  }
}

@media (max-height: 640px) {
  .village-tagline { display: none; }
}

/* Low screens: the panel keeps its text size but drops what the map already
   shows (pet face, place name) and the next-shard note, and puts Play and
   All levels on one row when both fit, so more of the map stays visible.
   A wrapping row (not a max-content grid column) keeps the panel inside the
   screen: the title wraps, and All levels moves under Play rather than being
   squeezed to one letter per line (320px, German/English/Arabic). */
@media (max-height: 700px) {
  .village-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 8px;
    padding: 10px 12px max(10px, env(safe-area-inset-bottom));
  }
  .village-panel-pet,
  .village-panel-area,
  .village-meter-next { display: none; }
  .village-panel-text,
  .village-panel > .village-panel-heading { flex: 1 1 100%; min-width: 0; }
  .village-panel-heading { margin: 0 0 4px; }
  .village-cta { flex: 1 0 auto; min-height: 46px; margin-top: 6px; padding: 0 12px; white-space: nowrap; }
  .village-link { flex: 0 0 auto; margin: 6px auto 0; line-height: 1.2; white-space: nowrap; }
}

/* ---------- Low screens ----------
   Below ~780px the prototype's percentage layout puts the stage-2 button on
   the shard chip and squeezes the islands under the panel. Here the button
   gets its own row under the chip, the map keeps a usable height and
   scrolls, the panel (with the play button) stays at the bottom, and the
   rail moves up beside the chip with five steps. Narrow phones up to 900px
   tall use it too, since their title can wrap onto the chip. */
@media (max-height: 780px), (max-width: 420px) and (max-height: 900px) {
  .village-header { min-height: calc(176px + var(--village-top-shift)); align-items: flex-start; }
  .village-stage-open {
    top: calc(126px + var(--village-top-shift));
    bottom: auto;
  }
  /* Right of the title, beside the chip: clear of the panel at any scroll. */
  .village-stage-nav {
    top: calc(64px + var(--village-top-shift));
    transform: none;
  }
  .village-stage-viewport { height: calc(5 * var(--stage-step)); }
}

/* Narrow and low: a title that wraps to two lines and a long stage label
   (EN "Stage 2 · Coming soon") get more room instead of smaller text — the
   chip and the stage button move down and the button wraps before the rail. */
@media (max-width: 420px) and (max-height: 900px) {
  .village-header { min-height: calc(210px + var(--village-top-shift)); padding-top: calc(94px + var(--village-top-shift)); }
  .village-stage-open {
    top: calc(144px + var(--village-top-shift));
    /* left: 50% would cap the width at half the screen; size to the text. */
    width: max-content;
    max-width: calc(100% - 100px);
    white-space: normal;
    text-align: center;
    line-height: 1.15;
    padding-top: 4px;
    padding-bottom: 4px;
  }
}

/* ---------- Narrow screens ----------
   The art stays full width, but the points and their route keep clear of
   the stage rail so it never covers an island name. */
@media (max-width: 420px) {
  .village-path,
  .village-areas { right: 44px; }
}
