{"id":87,"date":"2026-10-16T23:27:25","date_gmt":"2026-10-16T23:27:25","guid":{"rendered":"https:\/\/apk.produsenpagarbrc.com\/?p=87"},"modified":"2026-10-16T23:27:25","modified_gmt":"2026-10-16T23:27:25","slug":"mochimallet-nightdash","status":"publish","type":"post","link":"https:\/\/play.produsenpagarbrc.com\/?p=87","title":{"rendered":"Mochimallet Nightdash"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Mochimallet Nightdash is a fast-paced endless runner set inside the Moon Rabbit Workshop, a magical crafting station suspended above the sleeping world. Players guide Nori, a young moon rabbit apprentice, across a moving wooden workbench filled with mochi crates, toolboxes, lantern carts, hanging mallets, and drifting workshop cloth. The objective is to run as far as possible, collect glowing Moon Charms, avoid every obstacle, and help Nori complete an urgent delivery before the workshop\u2019s moonlight begins to fade.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game combines simple running controls with increasingly demanding timing. Nori moves forward automatically while players decide when to jump, duck, or use a temporary power-up. The route gradually becomes faster, forcing players to read incoming obstacles, react quickly, and maintain a steady rhythm. Every successful second increases the score, while collected Moon Charms and special items provide additional rewards.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/play.produsenpagarbrc.com\/wp-content\/uploads\/2026\/10\/Mochimallet-Nightdash-1024x768.png\" alt=\"\" class=\"wp-image-89\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">The Workshop That Keeps the Moon Glowing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">High above the clouds lies a wooden workshop that cannot be seen from the ground. Its windows open toward a deep plum sky, its lanterns burn with creamy lunar light, and its shelves are filled with tiny tools made for rabbit-sized paws. This is the Moon Rabbit Workshop, where generations of craftspeople prepare everything needed to keep the night peaceful.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The workshop creates more than ordinary objects. Its workers shape soft mochi that stores moonlight, carve wooden mallets that can repair broken cloud bridges, polish charms used to guide wandering stars, and sew violet cloth that protects the sky from cold celestial winds. Every finished item is delivered to a different station before dawn.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On the night when Mochimallet Nightdash begins, an unexpected cloudstorm shakes the workshop. Boxes slide across the counters, lantern carts roll away from their storage rails, and hanging tools begin swinging over the delivery route. At the same time, several Moon Charms scatter across the long central workbench.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The senior couriers are busy securing the outer platforms, so Nori, the smallest apprentice in the workshop, volunteers to carry the remaining supplies. Although Nori has never completed the entire night route alone, the young rabbit ties on a purple workshop scarf, secures a tiny tool pouch, and begins running across the enormous wooden counter.<\/p>\n\n\n\n<div id=\"mochimallet-nightdash-game\" aria-label=\"Mochimallet Nightdash, a Moon Rabbit Workshop endless runner game\">\n<style>\n#mochimallet-nightdash-game,\n#mochimallet-nightdash-game * {\n  box-sizing: border-box;\n  -webkit-tap-highlight-color: transparent;\n}\n\n#mochimallet-nightdash-game {\n  --mmn-night: #23142f;\n  --mmn-plum: #39244d;\n  --mmn-violet: #57406e;\n  --mmn-lavender: #8b78b8;\n  --mmn-cloud: #cfd1ff;\n  --mmn-cream: #fff1c9;\n  --mmn-ivory: #fff8e7;\n  --mmn-gold: #f4c542;\n  --mmn-wood: #7b5236;\n  --mmn-rose: #e58e96;\n  --mmn-danger: #d96f6f;\n  --mmn-ink: #2b1b34;\n  --mmn-muted: #71617b;\n  width: 100%;\n  max-width: 100%;\n  margin: 16px auto;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  isolation: isolate;\n  color-scheme: light;\n  font-family: Arial, Helvetica, sans-serif;\n  user-select: none;\n  -webkit-user-select: none;\n}\n\nhtml.is-dark #mochimallet-nightdash-game,\nbody.is-dark #mochimallet-nightdash-game {\n  --mmn-night: #130d1b;\n  --mmn-plum: #24172f;\n  --mmn-violet: #3d2b4d;\n  --mmn-lavender: #9b89c8;\n  --mmn-cloud: #d9dcff;\n  --mmn-cream: #f6e7bd;\n  --mmn-ivory: #f8f0df;\n  --mmn-gold: #e9bd4a;\n  --mmn-wood: #8d6347;\n  --mmn-rose: #d98c98;\n  --mmn-ink: #f8f0df;\n  --mmn-muted: #c3b8c8;\n  color-scheme: dark;\n}\n\n#mochimallet-nightdash-game button {\n  margin: 0;\n  border: 0;\n  font: inherit;\n}\n\n#mochimallet-nightdash-game .mmn-shell {\n  position: relative;\n  width: min(100%, 1120px, calc((100dvh - 20px) * 16 \/ 9));\n  min-width: 0;\n  margin: 0 auto;\n}\n\n#mochimallet-nightdash-game .mmn-frame {\n  position: relative;\n  width: 100%;\n  aspect-ratio: 16 \/ 9;\n  overflow: hidden;\n  border: 1px solid rgba(244, 197, 66, .34);\n  border-radius: clamp(18px, 2.2vw, 28px);\n  background:\n    radial-gradient(circle at 78% 10%, rgba(255, 241, 201, .22), transparent 27%),\n    linear-gradient(150deg, #2a1940, #4b3262 58%, #6d4b72);\n  box-shadow:\n    inset 0 0 0 1px rgba(255, 255, 255, .10),\n    0 26px 62px rgba(28, 15, 39, .30);\n}\n\nhtml.is-dark #mochimallet-nightdash-game .mmn-frame,\nbody.is-dark #mochimallet-nightdash-game .mmn-frame {\n  border-color: rgba(244, 197, 66, .26);\n  background:\n    radial-gradient(circle at 78% 10%, rgba(244, 197, 66, .11), transparent 28%),\n    linear-gradient(150deg, #130d1b, #24172f 58%, #3b2945);\n  box-shadow:\n    inset 0 0 0 1px rgba(255, 255, 255, .05),\n    0 28px 68px rgba(0, 0, 0, .42);\n}\n\n#mochimallet-nightdash-game .mmn-frame.mmn-modal-active .mmn-canvas {\n  filter: blur(1.6px) brightness(.62) saturate(.88);\n  transform: scale(1.008);\n}\n\n#mochimallet-nightdash-game .mmn-canvas {\n  position: absolute;\n  inset: 0;\n  width: 100%;\n  height: 100%;\n  display: block;\n  touch-action: none;\n  transition: filter .2s ease, transform .2s ease;\n}\n\n#mochimallet-nightdash-game .mmn-ui {\n  position: absolute;\n  inset: 0;\n  z-index: 5;\n  pointer-events: none;\n}\n\n#mochimallet-nightdash-game .mmn-topbar {\n  position: absolute;\n  top: clamp(10px, 1.35vw, 16px);\n  left: clamp(12px, 1.7vw, 20px);\n  right: clamp(12px, 1.7vw, 20px);\n  height: clamp(42px, 5.3vw, 58px);\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n}\n\n#mochimallet-nightdash-game .mmn-top-left,\n#mochimallet-nightdash-game .mmn-top-right {\n  display: flex;\n  align-items: center;\n  gap: clamp(6px, .8vw, 10px);\n  pointer-events: auto;\n}\n\n#mochimallet-nightdash-game .mmn-icon-button,\n#mochimallet-nightdash-game .mmn-action-button,\n#mochimallet-nightdash-game .mmn-popup-button {\n  appearance: none;\n  -webkit-appearance: none;\n  cursor: pointer;\n  touch-action: manipulation;\n}\n\n#mochimallet-nightdash-game .mmn-icon-button {\n  position: relative;\n  width: clamp(40px, 4.6vw, 50px);\n  height: clamp(40px, 4.6vw, 50px);\n  border: 1px solid rgba(244, 197, 66, .62);\n  border-radius: clamp(12px, 1.4vw, 16px);\n  color: var(--mmn-cream);\n  background:\n    radial-gradient(circle at 28% 14%, rgba(255,255,255,.16), transparent 31%),\n    linear-gradient(180deg, var(--mmn-violet), var(--mmn-plum));\n  box-shadow:\n    inset 0 1px 0 rgba(255,255,255,.16),\n    0 8px 20px rgba(28,15,39,.24);\n  transition: transform .15s ease, border-color .15s ease, filter .15s ease, box-shadow .15s ease;\n  pointer-events: auto;\n}\n\n#mochimallet-nightdash-game .mmn-icon-button:hover,\n#mochimallet-nightdash-game .mmn-icon-button:focus-visible,\n#mochimallet-nightdash-game .mmn-action-button:hover,\n#mochimallet-nightdash-game .mmn-action-button:focus-visible,\n#mochimallet-nightdash-game .mmn-popup-button:hover,\n#mochimallet-nightdash-game .mmn-popup-button:focus-visible {\n  outline: none;\n  transform: translateY(-2px);\n  border-color: var(--mmn-cream);\n  filter: brightness(1.07);\n  box-shadow:\n    0 0 0 3px rgba(244,197,66,.18),\n    0 13px 28px rgba(28,15,39,.30);\n}\n\n#mochimallet-nightdash-game .mmn-icon-button:active,\n#mochimallet-nightdash-game .mmn-action-button:active,\n#mochimallet-nightdash-game .mmn-popup-button:active {\n  transform: translateY(1px) scale(.98);\n}\n\n#mochimallet-nightdash-game button:focus-visible {\n  outline: 3px solid rgba(255,241,201,.92);\n  outline-offset: 3px;\n}\n\n#mochimallet-nightdash-game .mmn-score-wrap {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  display: flex;\n  gap: clamp(6px, .8vw, 10px);\n  pointer-events: none;\n}\n\n#mochimallet-nightdash-game .mmn-score-box {\n  min-width: clamp(76px, 9vw, 110px);\n  padding: clamp(6px, .75vw, 9px) clamp(8px, 1vw, 14px);\n  border: 1px solid rgba(244,197,66,.48);\n  border-radius: clamp(12px, 1.4vw, 16px);\n  text-align: center;\n  background:\n    radial-gradient(circle at 24% 12%, rgba(255,255,255,.16), transparent 34%),\n    linear-gradient(180deg, rgba(57,36,77,.94), rgba(35,20,47,.94));\n  box-shadow:\n    inset 0 1px 0 rgba(255,255,255,.12),\n    0 8px 20px rgba(28,15,39,.24);\n}\n\n#mochimallet-nightdash-game .mmn-score-label {\n  color: var(--mmn-cloud);\n  font-size: clamp(7px, .8vw, 10px);\n  line-height: 1;\n  font-weight: 900;\n  letter-spacing: .12em;\n  text-transform: uppercase;\n}\n\n#mochimallet-nightdash-game .mmn-score-value {\n  margin-top: 5px;\n  color: var(--mmn-cream);\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: clamp(13px, 1.6vw, 20px);\n  line-height: 1;\n  font-weight: 900;\n  font-variant-numeric: tabular-nums;\n}\n\n#mochimallet-nightdash-game .mmn-power-badge {\n  position: absolute;\n  left: 50%;\n  top: clamp(62px, 7.7vw, 84px);\n  transform: translateX(-50%);\n  min-width: clamp(160px, 21vw, 245px);\n  padding: 7px 13px;\n  border: 1px solid rgba(255,241,201,.62);\n  border-radius: 999px;\n  color: var(--mmn-night);\n  background: linear-gradient(90deg, var(--mmn-cream), var(--mmn-cloud), var(--mmn-gold));\n  box-shadow: 0 8px 19px rgba(28,15,39,.22);\n  font-size: clamp(8px, 1vw, 11px);\n  font-weight: 900;\n  letter-spacing: .05em;\n  text-align: center;\n  text-transform: uppercase;\n}\n\n#mochimallet-nightdash-game .mmn-power-badge[hidden] {\n  display: none;\n}\n\n#mochimallet-nightdash-game .mmn-bottom-controls {\n  position: absolute;\n  left: clamp(20px, 3.8vw, 42px);\n  right: clamp(20px, 3.8vw, 42px);\n  bottom: clamp(16px, 3.2vw, 32px);\n  display: flex;\n  align-items: flex-end;\n  justify-content: space-between;\n}\n\n#mochimallet-nightdash-game .mmn-action-button {\n  width: clamp(70px, 8.7vw, 94px);\n  height: clamp(70px, 8.7vw, 94px);\n  border: 2px solid rgba(255,241,201,.86);\n  border-radius: 50%;\n  color: var(--mmn-cream);\n  font-size: clamp(11px, 1.3vw, 14px);\n  font-weight: 900;\n  letter-spacing: .10em;\n  background:\n    radial-gradient(circle at 30% 20%, rgba(255,255,255,.24), transparent 28%),\n    linear-gradient(180deg, var(--mmn-lavender), var(--mmn-violet));\n  box-shadow:\n    inset 0 2px 0 rgba(255,255,255,.24),\n    inset 0 -12px 18px rgba(24,12,33,.14),\n    0 13px 28px rgba(28,15,39,.28);\n  pointer-events: auto;\n  transition: transform .14s ease, filter .14s ease, box-shadow .14s ease;\n}\n\n#mochimallet-nightdash-game .mmn-action-button:last-child {\n  background:\n    radial-gradient(circle at 30% 20%, rgba(255,255,255,.22), transparent 28%),\n    linear-gradient(180deg, var(--mmn-wood), #4d3126);\n}\n\n#mochimallet-nightdash-game .mmn-note {\n  position: absolute;\n  left: 50%;\n  bottom: clamp(18px, 3.4vw, 34px);\n  transform: translateX(-50%);\n  max-width: min(66%, 640px);\n  padding: 8px 13px;\n  border: 1px solid rgba(244,197,66,.48);\n  border-radius: 999px;\n  color: var(--mmn-night);\n  background: rgba(255,241,201,.95);\n  box-shadow: 0 8px 18px rgba(28,15,39,.22);\n  font-size: clamp(9px, 1.1vw, 12px);\n  line-height: 1.25;\n  text-align: center;\n  opacity: 0;\n  transition: opacity .22s ease;\n}\n\n#mochimallet-nightdash-game .mmn-note.mmn-show {\n  opacity: 1;\n}\n\n#mochimallet-nightdash-game .mmn-overlay {\n  position: absolute;\n  inset: 0;\n  z-index: 10;\n  display: none;\n  align-items: center;\n  justify-content: center;\n  padding: clamp(10px, 2vw, 24px);\n  overflow: hidden;\n  border-radius: inherit;\n  background:\n    radial-gradient(circle at 50% 22%, rgba(255,241,201,.14), transparent 36%),\n    rgba(20, 10, 30, .58);\n  backdrop-filter: blur(6px) saturate(.9);\n  -webkit-backdrop-filter: blur(6px) saturate(.9);\n}\n\n#mochimallet-nightdash-game .mmn-overlay.mmn-show {\n  display: flex;\n}\n\n#mochimallet-nightdash-game .mmn-overlay-fullscreen {\n  position: absolute;\n  top: clamp(11px, 1.5vw, 18px);\n  right: clamp(11px, 1.6vw, 20px);\n  z-index: 40;\n}\n\n#mochimallet-nightdash-game .mmn-popup {\n  position: relative;\n  width: min(82%, 420px);\n  max-height: min(84%, 430px);\n  overflow: hidden;\n  padding: clamp(20px, 2.6vw, 30px);\n  border: 1px solid rgba(244,197,66,.62);\n  border-radius: clamp(19px, 2.3vw, 27px);\n  color: var(--mmn-night);\n  text-align: center;\n  background:\n    radial-gradient(circle at 82% 2%, rgba(139,120,184,.20), transparent 35%),\n    linear-gradient(155deg, var(--mmn-ivory), var(--mmn-cream));\n  box-shadow:\n    inset 0 0 0 4px rgba(255,255,255,.22),\n    0 27px 66px rgba(20,10,30,.38);\n  animation: mmnPopupIn .22s ease both;\n  pointer-events: auto;\n}\n\n#mochimallet-nightdash-game .mmn-popup::before {\n  content: \"\";\n  display: block;\n  width: 64px;\n  height: 64px;\n  margin: 1px auto 12px;\n  border: 3px solid var(--mmn-wood);\n  border-radius: 50% 50% 40% 40%;\n  background:\n    radial-gradient(circle at 50% 60%, var(--mmn-cream) 0 14px, var(--mmn-rose) 15px 27px, var(--mmn-lavender) 28px 100%);\n  box-shadow:\n    inset 0 0 0 2px rgba(255,255,255,.22),\n    0 0 24px rgba(139,120,184,.28);\n}\n\n#mochimallet-nightdash-game .mmn-popup h2 {\n  margin: 0 0 9px;\n  color: var(--mmn-night);\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: clamp(21px, 3vw, 34px);\n  line-height: 1.05;\n  font-weight: 900;\n}\n\n#mochimallet-nightdash-game .mmn-popup p {\n  max-width: 350px;\n  margin: 0 auto 13px;\n  color: rgba(43,27,52,.80);\n  font-size: clamp(10px, 1.2vw, 13px);\n  line-height: 1.5;\n  font-weight: 650;\n}\n\n#mochimallet-nightdash-game .mmn-help {\n  max-width: 350px;\n  margin: 0 auto 14px;\n  padding: 8px 10px;\n  border: 1px solid rgba(139,120,184,.48);\n  border-radius: 14px;\n  color: rgba(43,27,52,.76);\n  background: rgba(139,120,184,.14);\n  font-size: clamp(9px, 1.08vw, 11.5px);\n  line-height: 1.4;\n}\n\n#mochimallet-nightdash-game .mmn-popup-actions {\n  display: flex;\n  justify-content: center;\n  gap: 9px;\n  flex-wrap: wrap;\n}\n\n#mochimallet-nightdash-game .mmn-popup-button {\n  min-width: 128px;\n  min-height: 42px;\n  padding: 0 17px;\n  border: 1px solid rgba(255,241,201,.84);\n  border-radius: 14px;\n  color: var(--mmn-cream);\n  background:\n    radial-gradient(circle at 24% 17%, rgba(255,255,255,.18), transparent 25%),\n    linear-gradient(180deg, var(--mmn-violet), var(--mmn-plum));\n  box-shadow:\n    inset 0 1px 0 rgba(255,255,255,.20),\n    0 9px 20px rgba(28,15,39,.24);\n  font-size: 12px;\n  font-weight: 900;\n  letter-spacing: .03em;\n  transition: transform .14s ease, border-color .14s ease, box-shadow .14s ease;\n}\n\n#mochimallet-nightdash-game .mmn-popup-button.mmn-secondary {\n  background: linear-gradient(180deg, var(--mmn-wood), #4d3126);\n}\n\n#mochimallet-nightdash-game .mmn-hidden {\n  display: none;\n}\n\n#mochimallet-nightdash-game .mmn-icon {\n  position: absolute;\n  inset: 0;\n  margin: auto;\n}\n\n#mochimallet-nightdash-game .mmn-pause-icon {\n  width: 20px;\n  height: 22px;\n}\n\n#mochimallet-nightdash-game .mmn-pause-icon::before,\n#mochimallet-nightdash-game .mmn-pause-icon::after {\n  content: \"\";\n  position: absolute;\n  top: 2px;\n  width: 6px;\n  height: 18px;\n  border-radius: 4px;\n  background: currentColor;\n}\n\n#mochimallet-nightdash-game .mmn-pause-icon::before { left: 2px; }\n#mochimallet-nightdash-game .mmn-pause-icon::after { right: 2px; }\n\n#mochimallet-nightdash-game .mmn-play-icon {\n  width: 21px;\n  height: 22px;\n}\n\n#mochimallet-nightdash-game .mmn-play-icon::before {\n  content: \"\";\n  position: absolute;\n  left: 4px;\n  top: 2px;\n  border-top: 9px solid transparent;\n  border-bottom: 9px solid transparent;\n  border-left: 15px solid currentColor;\n}\n\n#mochimallet-nightdash-game .mmn-sound-icon {\n  width: 28px;\n  height: 26px;\n}\n\n#mochimallet-nightdash-game .mmn-speaker-box {\n  position: absolute;\n  left: 0;\n  top: 9px;\n  width: 7px;\n  height: 9px;\n  border-radius: 3px;\n  background: currentColor;\n}\n\n#mochimallet-nightdash-game .mmn-speaker-cone {\n  position: absolute;\n  left: 5px;\n  top: 4px;\n  width: 12px;\n  height: 19px;\n  border-radius: 3px;\n  background: currentColor;\n  clip-path: polygon(0 34%, 100% 0, 100% 100%, 0 66%);\n}\n\n#mochimallet-nightdash-game .mmn-sound-wave {\n  position: absolute;\n  border-right: 2px solid currentColor;\n  border-top: 2px solid transparent;\n  border-bottom: 2px solid transparent;\n  border-radius: 50%;\n}\n\n#mochimallet-nightdash-game .mmn-wave-1 { right: 7px; top: 10px; width: 7px; height: 8px; }\n#mochimallet-nightdash-game .mmn-wave-2 { right: 2px; top: 6px; width: 12px; height: 16px; }\n#mochimallet-nightdash-game .mmn-wave-3 { right: -3px; top: 1px; width: 18px; height: 25px; opacity: .72; }\n\n#mochimallet-nightdash-game .mmn-sound-slash {\n  position: absolute;\n  left: -2px;\n  top: 11px;\n  width: 27px;\n  height: 4px;\n  border-radius: 99px;\n  background: var(--mmn-danger);\n  transform: rotate(-39deg);\n  opacity: 0;\n}\n\n#mochimallet-nightdash-game .mmn-muted .mmn-sound-wave { opacity: .10; }\n#mochimallet-nightdash-game .mmn-muted .mmn-sound-slash { opacity: 1; }\n\n#mochimallet-nightdash-game .mmn-fullscreen-icon {\n  width: 23px;\n  height: 23px;\n  display: block;\n  background:\n    linear-gradient(currentColor, currentColor) left top \/ 10px 3px no-repeat,\n    linear-gradient(currentColor, currentColor) left top \/ 3px 10px no-repeat,\n    linear-gradient(currentColor, currentColor) right top \/ 10px 3px no-repeat,\n    linear-gradient(currentColor, currentColor) right top \/ 3px 10px no-repeat,\n    linear-gradient(currentColor, currentColor) left bottom \/ 10px 3px no-repeat,\n    linear-gradient(currentColor, currentColor) left bottom \/ 3px 10px no-repeat,\n    linear-gradient(currentColor, currentColor) right bottom \/ 10px 3px no-repeat,\n    linear-gradient(currentColor, currentColor) right bottom \/ 3px 10px no-repeat;\n}\n\n#mochimallet-nightdash-game.mmn-fullscreen-active {\n  position: fixed;\n  inset: 0;\n  z-index: 2147483647;\n  width: 100dvw;\n  height: 100dvh;\n  max-width: none;\n  margin: 0;\n  padding: 0;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  overflow: hidden;\n  background:\n    radial-gradient(circle at 78% 12%, rgba(255,241,201,.14), transparent 28%),\n    linear-gradient(145deg, #130d1b, #2a1a3a 55%, #4a324f);\n}\n\n#mochimallet-nightdash-game.mmn-fullscreen-active .mmn-shell {\n  position: absolute;\n  left: var(--mmn-fs-center-x, 50vw);\n  top: var(--mmn-fs-center-y, 50vh);\n  width: var(--mmn-fs-shell-w, min(100vw, 177.777778vh));\n  height: var(--mmn-fs-shell-h, min(100vh, 56.25vw));\n  max-width: none;\n  max-height: none;\n  margin: 0;\n  transform: translate(-50%, -50%);\n}\n\n#mochimallet-nightdash-game.mmn-fullscreen-active .mmn-frame {\n  width: 100%;\n  height: 100%;\n  aspect-ratio: 16 \/ 9;\n  border: 0;\n  border-radius: 0;\n  box-shadow: none;\n}\n\n#mochimallet-nightdash-game:fullscreen::backdrop,\n#mochimallet-nightdash-game:-webkit-full-screen::backdrop {\n  background: linear-gradient(145deg, #130d1b, #2a1a3a 55%, #4a324f);\n}\n\n@keyframes mmnPopupIn {\n  from { opacity: 0; transform: translateY(8px) scale(.97); }\n  to { opacity: 1; transform: translateY(0) scale(1); }\n}\n\n@media (max-width: 680px), (max-height: 430px) {\n  #mochimallet-nightdash-game { margin: 10px auto; }\n  #mochimallet-nightdash-game .mmn-frame { border-radius: 18px; }\n  #mochimallet-nightdash-game .mmn-topbar { top: 8px; left: 9px; right: 9px; }\n  #mochimallet-nightdash-game .mmn-icon-button { width: 39px; height: 39px; border-radius: 12px; }\n  #mochimallet-nightdash-game .mmn-score-box { min-width: 60px; padding: 5px 6px 6px; }\n  #mochimallet-nightdash-game .mmn-action-button { width: 68px; height: 68px; font-size: 10px; }\n  #mochimallet-nightdash-game .mmn-bottom-controls { left: 16px; right: 16px; bottom: 13px; }\n  #mochimallet-nightdash-game .mmn-note { bottom: 15px; max-width: 58%; font-size: 9px; }\n  #mochimallet-nightdash-game .mmn-power-badge { top: 55px; padding: 5px 9px; }\n  #mochimallet-nightdash-game .mmn-popup { width: min(88%, 360px); max-height: 92%; padding: 7px 9px; }\n  #mochimallet-nightdash-game .mmn-popup::before { width: 28px; height: 28px; margin: 0 auto 3px; border-width: 2px; }\n  #mochimallet-nightdash-game .mmn-popup h2 { margin-bottom: 3px; font-size: 14px; line-height: 1; }\n  #mochimallet-nightdash-game .mmn-popup p { display: none; }\n  #mochimallet-nightdash-game .mmn-help { margin-bottom: 5px; padding: 4px 6px; font-size: 7px; line-height: 1.18; }\n  #mochimallet-nightdash-game .mmn-popup-actions { gap: 4px; }\n  #mochimallet-nightdash-game .mmn-popup-button { min-width: 108px; min-height: 28px; padding: 0 8px; border-radius: 10px; font-size: 8px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  #mochimallet-nightdash-game *,\n  #mochimallet-nightdash-game *::before,\n  #mochimallet-nightdash-game *::after {\n    animation-duration: .01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: .01ms !important;\n  }\n}\n<\/style>\n\n<div class=\"mmn-shell\">\n  <div class=\"mmn-frame\">\n    <canvas class=\"mmn-canvas\" aria-label=\"Mochimallet Nightdash moon rabbit workshop endless runner\"><\/canvas>\n\n    <div class=\"mmn-ui\">\n      <div class=\"mmn-topbar\">\n        <div class=\"mmn-top-left\">\n          <button class=\"mmn-icon-button\" type=\"button\" data-mmn-action=\"pause\" aria-label=\"Pause game\">\n            <span class=\"mmn-icon mmn-pause-icon\" data-mmn-pause-icon><\/span>\n          <\/button>\n\n          <button class=\"mmn-icon-button\" type=\"button\" data-mmn-action=\"sound\" aria-label=\"Mute sound\">\n            <span class=\"mmn-icon mmn-sound-icon\">\n              <span class=\"mmn-speaker-box\"><\/span>\n              <span class=\"mmn-speaker-cone\"><\/span>\n              <span class=\"mmn-sound-wave mmn-wave-1\"><\/span>\n              <span class=\"mmn-sound-wave mmn-wave-2\"><\/span>\n              <span class=\"mmn-sound-wave mmn-wave-3\"><\/span>\n              <span class=\"mmn-sound-slash\"><\/span>\n            <\/span>\n          <\/button>\n        <\/div>\n\n        <div class=\"mmn-score-wrap\" aria-live=\"polite\">\n          <div class=\"mmn-score-box\">\n            <div class=\"mmn-score-label\">Distance<\/div>\n            <div class=\"mmn-score-value\" data-mmn-score>0000<\/div>\n          <\/div>\n          <div class=\"mmn-score-box\">\n            <div class=\"mmn-score-label\">Best<\/div>\n            <div class=\"mmn-score-value\" data-mmn-best>0000<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"mmn-top-right\">\n          <button class=\"mmn-icon-button\" type=\"button\" data-mmn-action=\"fullscreen\" aria-label=\"Toggle fullscreen\">\n            <span class=\"mmn-icon mmn-fullscreen-icon\"><\/span>\n          <\/button>\n        <\/div>\n      <\/div>\n\n      <div class=\"mmn-power-badge\" data-mmn-power hidden><\/div>\n\n      <div class=\"mmn-note\" data-mmn-note>\n        Collect Moon Charms. Mochi Moon Shield absorbs one collision, while Cloudspring grants one extra midair jump.\n      <\/div>\n\n      <div class=\"mmn-bottom-controls\">\n        <button class=\"mmn-action-button\" type=\"button\" data-mmn-action=\"jump\" aria-label=\"Jump\">JUMP<\/button>\n        <button class=\"mmn-action-button\" type=\"button\" data-mmn-action=\"duck\" aria-label=\"Duck\">DUCK<\/button>\n      <\/div>\n    <\/div>\n\n    <div class=\"mmn-overlay mmn-show\" data-mmn-overlay>\n      <button class=\"mmn-icon-button mmn-overlay-fullscreen\" type=\"button\" data-mmn-action=\"fullscreen\" aria-label=\"Toggle fullscreen\">\n        <span class=\"mmn-icon mmn-fullscreen-icon\"><\/span>\n      <\/button>\n\n      <div class=\"mmn-popup\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"mmn-popup-title\">\n        <h2 id=\"mmn-popup-title\" data-mmn-popup-title>The Night Workshop Route Opens<\/h2>\n        <p data-mmn-popup-text>\n          Guide Nori, a young moon-rabbit apprentice, across the moving workshop bench. Leap over mochi crates, toolboxes, and lantern carts, then duck beneath mallet racks and hanging mooncloth while collecting Moon Charms.\n        <\/p>\n        <div class=\"mmn-help\" data-mmn-popup-help>\n          Desktop: Space, W, or Arrow Up to jump. S or Arrow Down to duck. Mobile: use the two lower buttons.\n        <\/div>\n        <div class=\"mmn-popup-actions\">\n          <button class=\"mmn-popup-button\" type=\"button\" data-mmn-action=\"main\">Begin the Moonlit Shift<\/button>\n          <button class=\"mmn-popup-button mmn-secondary mmn-hidden\" type=\"button\" data-mmn-action=\"restart\">Restart the Workshop Route<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function () {\n      \"use strict\";\n      function initializeMochimallet() {\n      const root = document.getElementById(\"mochimallet-nightdash-game\");\n      if (!root || root.dataset.mmnReady === \"1\") return;\n      root.dataset.mmnReady = \"1\";\n\n      const frame = root.querySelector(\".mmn-frame\");\n      const canvas = root.querySelector(\".mmn-canvas\");\n      const ctx = canvas.getContext(\"2d\", { alpha: true });\n      if (!ctx) return;\n      root.tabIndex = 0;\n      canvas.tabIndex = 0;\n      let gameInView = true;\n      if (typeof IntersectionObserver !== \"undefined\") {\n        const gameObserver = new IntersectionObserver(function (entries) {\n          gameInView = entries[0].isIntersecting;\n          if (gameInView) state.lastTime = performance.now();\n          else { input.jumpHeld = false; setDuck(false); }\n        }, { threshold: 0.01 });\n        gameObserver.observe(root);\n      }\n\n\n      const soundButton = root.querySelector('[data-mmn-action=\"sound\"]');\n      const pauseIcon = root.querySelector(\"[data-mmn-pause-icon]\");\n      const scoreEl = root.querySelector(\"[data-mmn-score]\");\n      const bestEl = root.querySelector(\"[data-mmn-best]\");\n      const powerEl = root.querySelector(\"[data-mmn-power]\");\n      const noteEl = root.querySelector(\"[data-mmn-note]\");\n      const overlay = root.querySelector(\"[data-mmn-overlay]\");\n      const popupTitle = root.querySelector(\"[data-mmn-popup-title]\");\n      const popupText = root.querySelector(\"[data-mmn-popup-text]\");\n      const popupHelp = root.querySelector(\"[data-mmn-popup-help]\");\n      const mainButton = root.querySelector('[data-mmn-action=\"main\"]');\n      const restartButton = root.querySelector('[data-mmn-action=\"restart\"]');\n\n      const DESIGN_W = 1280;\n      const DESIGN_H = 720;\n      const GROUND_Y = 578;\n      const BEST_KEY = \"moonRabbit_mochimalletNightdash_best_v1\";\n      const MUTE_KEY = \"moonRabbit_mochimalletNightdash_muted_v1\";\n\n      const state = {\n        mode: \"start\",\n        muted: safeGet(MUTE_KEY) === \"1\",\n        score: 0,\n        best: parseInt(safeGet(BEST_KEY) || \"0\", 10) || 0,\n        speed: 450,\n        targetSpeed: 450,\n        elapsed: 0,\n        spawnTimer: 1.55,\n        mochiShieldTimer: 0,\n        mochiShieldHits: 0,\n        cloudSpringTimer: 0,\n        noteTimer: 0,\n        milestone: 0,\n        lastObstacle: \"\",\n        shake: 0,\n        dpr: 1,\n        lastTime: 0,\n        roadOffset: 0\n      };\n\n      const input = {\n        jumpHeld: false,\n        duckHeld: false\n      };\n\n      const world = {\n        player: null,\n        obstacles: [],\n        pickups: [],\n        particles: []\n      };\n\n      let audio = null;\n      let resizeTimer = 0;\n      let fallbackFullscreen = false;\n\n      function safeGet(key) {\n        try { return localStorage.getItem(key); } catch (error) { return null; }\n      }\n\n      function safeSet(key, value) {\n        try { localStorage.setItem(key, value); } catch (error) {}\n      }\n\n      function clamp(value, min, max) {\n        return Math.max(min, Math.min(max, value));\n      }\n\n      function random(min, max) {\n        return Math.random() * (max - min) + min;\n      }\n\n      function chance(value) {\n        return Math.random() < value;\n      }\n\n      function darkTheme() {\n        return document.documentElement.classList.contains(\"is-dark\") ||\n          document.body.classList.contains(\"is-dark\") ||\n          document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n          document.body.getAttribute(\"data-theme\") === \"dark\";\n      }\n\n      function formatScore(value) {\n        const number = Math.floor(value);\n        return number < 10000 ? String(number).padStart(4, \"0\") : String(number);\n      }\n\n      function createPlayer() {\n        return {\n          x: 184,\n          y: GROUND_Y - 128,\n          w: 82,\n          h: 128,\n          baseW: 82,\n          baseH: 128,\n          vy: 0,\n          grounded: true,\n          ducking: false,\n          usedDouble: false,\n          phase: 0,\n          hold: 0\n        };\n      }\n\n      function resetRun() {\n        world.player = createPlayer();\n        world.obstacles = [];\n        world.pickups = [];\n        world.particles = [];\n        state.score = 0;\n        state.speed = 450;\n        state.targetSpeed = 450;\n        state.elapsed = 0;\n        state.spawnTimer = 1.55;\n        state.mochiShieldTimer = 0;\n        state.mochiShieldHits = 0;\n        state.cloudSpringTimer = 0;\n        state.noteTimer = 3.2;\n        state.milestone = 0;\n        state.lastObstacle = \"\";\n        state.shake = 0;\n        state.roadOffset = 0;\n        input.jumpHeld = false;\n        input.duckHeld = false;\n        updateHud();\n      }\n\n      function resize() {\n        syncFullscreenMetrics();\n        const rect = frame.getBoundingClientRect();\n        const cssW = Math.max(1, frame.offsetWidth || rect.width || DESIGN_W);\n        const cssH = Math.max(1, frame.offsetHeight || rect.height || DESIGN_H);\n        state.dpr = Math.min(window.devicePixelRatio || 1, 2);\n        canvas.width = Math.max(1, Math.round(cssW * state.dpr));\n        canvas.height = Math.max(1, Math.round(cssH * state.dpr));\n        canvas.style.width = cssW + \"px\";\n        canvas.style.height = cssH + \"px\";\n        ctx.setTransform(canvas.width \/ DESIGN_W, 0, 0, canvas.height \/ DESIGN_H, 0, 0);\n        ctx.imageSmoothingEnabled = true;\n        if (!world.player) world.player = createPlayer();\n      }\n\n      function scheduleResize(delay) {\n        clearTimeout(resizeTimer);\n        resizeTimer = setTimeout(resize, delay || 0);\n      }\n\n      function ensureAudio() {\n        if (state.muted) return null;\n        try {\n          if (!audio) {\n            const AudioClass = window.AudioContext || window.webkitAudioContext;\n            if (!AudioClass) return null;\n            audio = new AudioClass();\n          }\n          if (audio.state === \"suspended\") audio.resume();\n          return audio;\n        } catch (error) {\n          return null;\n        }\n      }\n\n      function tone(frequency, duration, volume, endFrequency, type) {\n        if (state.muted) return;\n        const ac = ensureAudio();\n        if (!ac) return;\n        const now = ac.currentTime;\n        const oscillator = ac.createOscillator();\n        const gain = ac.createGain();\n        oscillator.type = type || \"sine\";\n        oscillator.frequency.setValueAtTime(frequency, now);\n        if (endFrequency) oscillator.frequency.exponentialRampToValueAtTime(Math.max(20, endFrequency), now + duration);\n        gain.gain.setValueAtTime(.0001, now);\n        gain.gain.exponentialRampToValueAtTime(clamp(volume || .016, .0001, .08), now + .012);\n        gain.gain.exponentialRampToValueAtTime(.0001, now + duration);\n        oscillator.connect(gain);\n        gain.connect(ac.destination);\n        oscillator.start(now);\n        oscillator.stop(now + duration + .03);\n      }\n\n      function sound(type) {\n        if (type === \"click\") tone(420, .07, .012, 540, \"triangle\");\n        else if (type === \"jump\") { tone(390, .1, .016, 690, \"triangle\"); setTimeout(function () { tone(850, .07, .009, 1040); }, 38); }\n        else if (type === \"double\") { tone(570, .09, .018, 920, \"triangle\"); setTimeout(function () { tone(1120, .1, .011, 1420); }, 45); }\n        else if (type === \"duck\") tone(220, .075, .014, 155, \"triangle\");\n        else if (type === \"moonCharm\") { tone(810, .065, .014, 1060); setTimeout(function () { tone(1270, .07, .009, 1480, \"triangle\"); }, 34); }\n        else if (type === \"power\") { tone(470, .09, .017, 690, \"triangle\"); setTimeout(function () { tone(760, .1, .013, 1020); }, 55); }\n        else if (type === \"shield\") { tone(280, .09, .018, 190, \"triangle\"); setTimeout(function () { tone(520, .12, .012, 720); }, 58); }\n        else if (type === \"hit\") { tone(165, .19, .024, 92); setTimeout(function () { tone(108, .12, .013, 76, \"triangle\"); }, 52); }\n        else if (type === \"milestone\") { tone(480, .075, .017, 630, \"triangle\"); setTimeout(function () { tone(740, .085, .014, 950); }, 56); setTimeout(function () { tone(1090, .12, .012, 1460); }, 118); }\n      }\n\n      function updateHud() {\n        scoreEl.textContent = formatScore(state.score);\n        bestEl.textContent = formatScore(state.best);\n\n        const parts = [];\n\n        if ((state.mode === \"playing\" || state.mode === \"paused\") ? (state.mochiShieldTimer > 0 ? state.mochiShieldHits > 0 : false) : false) {\n          parts.push(\"Mochi Moon Shield \" + Math.max(1, Math.ceil(state.mochiShieldTimer)));\n        }\n\n        if ((state.mode === \"playing\" || state.mode === \"paused\") ? state.cloudSpringTimer > 0 : false) {\n          parts.push(\"Cloudspring \" + Math.max(1, Math.ceil(state.cloudSpringTimer)));\n        }\n\n        powerEl.textContent = parts.join(\"  \u2022  \");\n        powerEl.hidden = parts.length === 0;\n      }\n\n      function setMode(mode) {\n        state.mode = mode;\n\n        if (mode === \"playing\") {\n          overlay.classList.remove(\"mmn-show\");\n          frame.classList.remove(\"mmn-modal-active\");\n          pauseIcon.className = \"mmn-icon mmn-pause-icon\";\n        } else {\n          overlay.classList.add(\"mmn-show\");\n          frame.classList.add(\"mmn-modal-active\");\n          pauseIcon.className = mode === \"paused\" ? \"mmn-icon mmn-play-icon\" : \"mmn-icon mmn-pause-icon\";\n\n          if (mode === \"start\") {\n            popupTitle.textContent = \"The Night Workshop Route Opens\";\n            popupText.textContent = \"Guide Nori, a young moon-rabbit apprentice, across the moving workshop bench. Leap over mochi crates, toolboxes, and rolling lantern carts, then duck beneath mallet racks and hanging mooncloth while collecting Moon Charms.\";\n            popupHelp.textContent = \"Desktop: Space, W, or Arrow Up to jump. S or Arrow Down to duck. Mobile: use the two lower buttons.\";\n            mainButton.textContent = \"Begin the Moonlit Shift\";\n            restartButton.classList.add(\"mmn-hidden\");\n          } else if (mode === \"paused\") {\n            popupTitle.textContent = \"The Workshop Bell Is Quiet\";\n            popupText.textContent = \"Nori waits beside the moonwood bench while the workshop rests safely between cloud routes.\";\n            popupHelp.textContent = \"Mochi Moon Shield protects against one collision. Cloudspring grants one additional midair jump.\";\n            mainButton.textContent = \"Resume the Moonlit Shift\";\n            restartButton.textContent = \"Restart the Workshop Route\";\n            restartButton.classList.remove(\"mmn-hidden\");\n          } else {\n            popupTitle.textContent = \"The Moonlit Route Broke\";\n            popupText.textContent = \"Nori stumbled before the next cloud platform, but the Moon Rabbit Workshop is ready for another run.\";\n            popupHelp.textContent = \"Your best moonlit distance is saved automatically in this browser.\";\n            mainButton.textContent = \"Run the Workshop Again\";\n            restartButton.classList.add(\"mmn-hidden\");\n          }\n        }\n\n        updateHud();\n      }\n\n      function startGame() {\n        sound(\"click\");\n        resetRun();\n        setMode(\"playing\");\n        state.lastTime = performance.now();\n        root.focus({ preventScroll: true });\n        noteEl.classList.add(\"mmn-show\");\n      }\n\n      function pauseGame() {\n        if (state.mode !== \"playing\") return;\n        sound(\"click\");\n        setMode(\"paused\");\n      }\n\n      function resumeGame() {\n        if (state.mode !== \"paused\") return;\n        sound(\"click\");\n        setMode(\"playing\");\n        state.lastTime = performance.now();\n      }\n\n      function gameOver() {\n        if (state.mode !== \"playing\") return;\n        if (state.score > state.best) {\n          state.best = Math.floor(state.score);\n          safeSet(BEST_KEY, state.best);\n        }\n        state.shake = .22;\n        sound(\"hit\");\n        setMode(\"gameover\");\n      }\n\n      function emit(x, y, count, colors, spread) {\n        const palette = colors || [\"#efe1c9\", \"#e1bb87\", \"#b77842\"];\n        for (let i = 0; i < count; i++) {\n          const life = random(.34, .78);\n          world.particles.push({\n            x: x,\n            y: y,\n            vx: random(-78, 78) * (spread || 1),\n            vy: random(-135, 12) * (spread || 1),\n            life: life,\n            maxLife: life,\n            size: random(2.5, 7),\n            color: palette[(Math.random() * palette.length) | 0],\n            star: chance(.42)\n          });\n        }\n      }\n\n      function jump() {\n        const player = world.player;\n        if (state.mode === \"start\" || state.mode === \"gameover\") {\n          startGame();\n          return;\n        }\n        if (state.mode !== \"playing\" || !player) return;\n\n        if (player.grounded) {\n          player.grounded = false;\n          player.usedDouble = false;\n          player.vy = -735;\n          player.hold = .12;\n          input.jumpHeld = true;\n          sound(\"jump\");\n          emit(player.x + player.w * .45, GROUND_Y - 4, 7, [\"#a24f45\", \"#f4e4c9\", \"#e1bb87\"], .9);\n        } else if (state.cloudSpringTimer > 0 ? !player.usedDouble : false) {\n          player.usedDouble = true;\n          player.vy = -640;\n          player.hold = .08;\n          input.jumpHeld = true;\n          sound(\"double\");\n          emit(player.x + player.w * .48, player.y + player.h * .75, 12, [\"#efe1c9\", \"#e1bb87\", \"#b77842\"], 1.2);\n        }\n      }\n\n      function setDuck(active) {\n        const player = world.player;\n        input.duckHeld = active;\n        if (active ? (player ? (player.grounded ? (!player.ducking ? state.mode === \"playing\" : false) : false) : false) : false) sound(\"duck\");\n      }\n\n      function spawnMoonCharmTrail(startX) {\n        const count = Math.floor(random(3, 7));\n        const baseY = GROUND_Y - random(140, 215);\n        const arc = random(28, 58);\n        const spacing = 48;\n        for (let i = 0; i < count; i++) {\n          const ratio = count > 1 ? i \/ (count - 1) : 0;\n          world.pickups.push({\n            type: \"moonCharm\",\n            x: startX + i * spacing,\n            y: baseY - Math.sin(ratio * Math.PI) * arc,\n            r: 16,\n            bob: random(0, Math.PI * 2),\n            spin: random(0, Math.PI * 2)\n          });\n        }\n      }\n\n      function spawnPower(startX) {\n        world.pickups.push({\n          type: chance(.5) ? \"mochiShield\" : \"cloudSpring\",\n          x: startX,\n          y: GROUND_Y - random(180, 242),\n          r: 25,\n          bob: random(0, Math.PI * 2),\n          spin: random(0, Math.PI * 2)\n        });\n      }\n\n      function spawnObstacle() {\n        const choices = [\"mochiCrates\", \"toolboxes\"];\n\n        if (state.score >= 130) choices.push(\"lanternCart\");\n        if (state.score >= 230) choices.push(\"malletRack\", \"moonclothBanners\", \"malletRack\", \"moonclothBanners\");\n\n        let kind = choices[(Math.random() * choices.length) | 0];\n\n        if (kind === state.lastObstacle ? chance(.7) : false) {\n          kind = choices[(Math.random() * choices.length) | 0];\n        }\n\n        let obstacle;\n\n        if (kind === \"mochiCrates\") {\n          const w = random(94, 122);\n          const h = random(90, 122);\n          obstacle = {\n            kind: kind,\n            lane: \"ground\",\n            x: DESIGN_W + w + random(18, 48),\n            y: GROUND_Y - h,\n            w: w,\n            h: h,\n            hit: { x:.09, y:.10, w:.82, h:.87 }\n          };\n        } else if (kind === \"toolboxes\") {\n          const w = random(104, 136);\n          const h = random(88, 118);\n          obstacle = {\n            kind: kind,\n            lane: \"ground\",\n            x: DESIGN_W + w + random(18, 48),\n            y: GROUND_Y - h,\n            w: w,\n            h: h,\n            hit: { x:.08, y:.08, w:.84, h:.89 }\n          };\n        } else if (kind === \"lanternCart\") {\n          const w = random(142, 172);\n          const h = random(92, 118);\n          obstacle = {\n            kind: kind,\n            lane: \"ground\",\n            x: DESIGN_W + w + random(20, 54),\n            y: GROUND_Y - h,\n            w: w,\n            h: h,\n            hit: { x:.07, y:.12, w:.86, h:.80 }\n          };\n        } else {\n          const w = random(178, 232);\n          const lowerEdge = GROUND_Y - random(104, 120);\n          const x = DESIGN_W + w + random(18, 58);\n          obstacle = {\n            kind: kind,\n            lane: \"duck\",\n            x: x,\n            prevX: x,\n            y: 0,\n            w: w,\n            h: lowerEdge,\n            phase: random(0, Math.PI * 2),\n            hit: { x:.04, y:.82, w:.92, h:.18 }\n          };\n        }\n\n        world.obstacles.push(obstacle);\n        state.lastObstacle = kind;\n\n        const difficulty = clamp(state.score \/ 4500, 0, 1);\n        let gap = random(DESIGN_W * (.64 - difficulty * .04), DESIGN_W * (.99 - difficulty * .07));\n\n        if (obstacle.lane === \"duck\") gap += random(DESIGN_W * .08, DESIGN_W * .17);\n        if (chance(.18)) gap += random(DESIGN_W * .12, DESIGN_W * .24);\n        if (chance(.12)) gap -= DESIGN_W * .05;\n\n        gap = clamp(gap, DESIGN_W * .59, DESIGN_W * 1.15);\n\n        if (chance(.49)) spawnMoonCharmTrail(obstacle.x + obstacle.w + random(200, 390));\n        if (state.score > 360 ? chance(.13) : false) spawnPower(obstacle.x + obstacle.w + random(430, 650));\n\n        state.spawnTimer = gap \/ Math.max(1, state.speed);\n      }\n\n      function getPlayerBox() {\n        const p = world.player;\n        return { x:p.x+p.w*.22, y:p.y+p.h*.1, w:p.w*.56, h:p.h*.82 };\n      }\n\n      function getObstacleBox(o) {\n        return { x:o.x+o.w*o.hit.x, y:o.y+o.h*o.hit.y, w:o.w*o.hit.w, h:o.h*o.hit.h };\n      }\n\n      function overlap(a,b) {\n        return a.x < b.x+b.w ? (a.x+a.w > b.x ? (a.y < b.y+b.h ? a.y+a.h > b.y : false) : false) : false;\n      }\n\n      function circleRect(c,r) {\n        const nx = clamp(c.x, r.x, r.x+r.w);\n        const ny = clamp(c.y, r.y, r.y+r.h);\n        const dx = c.x-nx;\n        const dy = c.y-ny;\n        return dx*dx+dy*dy <= c.r*c.r;\n      }\n\n      function obstacleHits(o, playerBox) {\n        if (o.lane !== \"duck\") return overlap(playerBox, getObstacleBox(o));\n        const p = world.player;\n        const box = getObstacleBox(o);\n        const previousX = Number.isFinite(o.prevX) ? o.prevX : o.x;\n        const padding = Math.max(6, state.speed * .03);\n        const left = Math.min(previousX, o.x) - padding;\n        const right = Math.max(previousX + o.w, o.x + o.w) + padding;\n        const horizontal = playerBox.x < right ? playerBox.x + playerBox.w > left : false;\n        if (!horizontal) return false;\n        if (p.grounded ? p.ducking : false) return false;\n        const highJump = !p.grounded ? (p.usedDouble ? playerBox.y + playerBox.h < box.y + box.h * .5 : false) : false;\n        return !highJump;\n      }\n\n      function collect(pickup) {\n        if (pickup.type === \"moonCharm\") {\n          state.score += 35;\n          sound(\"moonCharm\");\n          emit(pickup.x, pickup.y, 8, [\"#fffaf0\",\"#d99a5f\",\"#e1bb87\",\"#315f44\"], .85);\n        } else if (pickup.type === \"mochiShield\") {\n          state.mochiShieldTimer = 10;\n          state.mochiShieldHits = 1;\n          state.score += 45;\n          sound(\"power\");\n          emit(pickup.x, pickup.y, 14, [\"#d99a5f\",\"#fffaf0\",\"#d99a5f\",\"#e1bb87\"], 1.2);\n        } else {\n          state.cloudSpringTimer = 10;\n          state.score += 45;\n          sound(\"power\");\n          emit(pickup.x, pickup.y, 14, [\"#fffaf0\",\"#e1bb87\",\"#315f44\",\"#a24f45\"], 1.2);\n        }\n      }\n\n      function updateParticles(dt) {\n        for (let i = world.particles.length - 1; i >= 0; i--) {\n          const p = world.particles[i];\n          p.life -= dt;\n          p.x += p.vx * dt;\n          p.y += p.vy * dt;\n          p.vy += 820 * dt;\n          if (p.life <= 0) world.particles.splice(i,1);\n        }\n      }\n\n      function update(dt) {\n        if (state.noteTimer > 0) {\n          state.noteTimer -= dt;\n          if (state.noteTimer <= 0) noteEl.classList.remove(\"mmn-show\");\n        }\n        state.shake = Math.max(0, state.shake - dt);\n        if (state.mochiShieldTimer > 0) {\n          state.mochiShieldTimer = Math.max(0, state.mochiShieldTimer - dt);\n          if (state.mochiShieldTimer <= 0) state.mochiShieldHits = 0;\n        }\n        if (state.cloudSpringTimer > 0) state.cloudSpringTimer = Math.max(0, state.cloudSpringTimer - dt);\n\n        state.elapsed += dt;\n        state.targetSpeed = Math.min(450 + state.elapsed * 11.5, 800);\n        state.speed += (state.targetSpeed - state.speed) * Math.min(1, dt * 3.5);\n        state.roadOffset += state.speed * dt;\n        state.score += dt * 18 + (state.speed \/ DESIGN_W) * 2.4;\n\n        const milestone = Math.floor(state.score \/ 1000);\n        if (milestone > state.milestone) {\n          state.milestone = milestone;\n          sound(\"milestone\");\n          emit(DESIGN_W * .5, 54, 16, [\"#fffaf0\",\"#b77842\",\"#789070\",\"#5f7e5e\"], 1.4);\n        }\n\n        const p = world.player;\n        if (p.grounded) {\n          if (input.duckHeld) {\n            p.ducking = true;\n            p.h = p.baseH * .68;\n            p.w = p.baseW * 1.08;\n          } else {\n            p.ducking = false;\n            p.h = p.baseH;\n            p.w = p.baseW;\n          }\n          p.y = GROUND_Y - p.h;\n          p.usedDouble = false;\n        } else {\n          if (input.jumpHeld ? (p.vy < 0 ? p.hold > 0 : false) : false) {\n            p.vy -= 1370 * dt;\n            p.hold -= dt;\n          }\n          p.vy += 1940 * dt;\n          if (input.duckHeld) p.vy += 3150 * dt;\n          p.y += p.vy * dt;\n          if (p.y + p.h >= GROUND_Y) {\n            p.y = GROUND_Y - p.h;\n            p.vy = 0;\n            p.grounded = true;\n            p.usedDouble = false;\n            emit(p.x+p.w*.44, GROUND_Y-4, 8, [\"#b77842\",\"#efe1c9\",\"#789070\"], .9);\n          }\n        }\n        p.phase += dt * (state.speed \/ 300);\n\n        state.spawnTimer -= dt;\n        if (state.spawnTimer <= 0) spawnObstacle();\n\n        for (let i = world.obstacles.length - 1; i >= 0; i--) {\n          const o = world.obstacles[i];\n          o.prevX = o.x;\n          o.x -= state.speed * dt;\n          if (o.x + o.w < -80) world.obstacles.splice(i,1);\n        }\n\n        for (let i = world.pickups.length - 1; i >= 0; i--) {\n          const pickup = world.pickups[i];\n          pickup.x -= state.speed * dt;\n          pickup.bob += dt * 4;\n          pickup.spin += dt * 7;\n          if (pickup.x + pickup.r < -50) world.pickups.splice(i,1);\n        }\n\n        const playerBox = getPlayerBox();\n\n        for (let i = world.pickups.length - 1; i >= 0; i--) {\n          const pickup = world.pickups[i];\n          const circle = { x:pickup.x, y:pickup.y+Math.sin(pickup.bob)*4, r:pickup.r };\n          if (circleRect(circle, playerBox)) {\n            collect(pickup);\n            world.pickups.splice(i,1);\n          }\n        }\n\n        for (let i = world.obstacles.length - 1; i >= 0; i--) {\n          const o = world.obstacles[i];\n          if (!obstacleHits(o, playerBox)) continue;\n          const box = getObstacleBox(o);\n          if (state.mochiShieldHits > 0) {\n            state.mochiShieldHits = 0;\n            state.mochiShieldTimer = 0;\n            state.score += 35;\n            sound(\"shield\");\n            emit(box.x+box.w*.5, box.y+box.h*.5, 24, [\"#e1bb87\",\"#fffaf0\",\"#789070\",\"#b77842\"], 1.5);\n            world.obstacles.splice(i,1);\n          } else {\n            emit(playerBox.x+playerBox.w*.5, playerBox.y+playerBox.h*.5, 26, [\"#fffaf0\",\"#a24f45\",\"#b77842\",\"#789070\"], 1.5);\n            gameOver();\n          }\n          break;\n        }\n\n        updateParticles(dt);\n        updateHud();\n      }\n\n      function roundedRect(x,y,w,h,r,fill,stroke) {\n        const radius = Math.min(r,w*.5,h*.5);\n        ctx.beginPath();\n        ctx.moveTo(x+radius,y);\n        ctx.arcTo(x+w,y,x+w,y+h,radius);\n        ctx.arcTo(x+w,y+h,x,y+h,radius);\n        ctx.arcTo(x,y+h,x,y,radius);\n        ctx.arcTo(x,y,x+w,y,radius);\n        ctx.closePath();\n        if (fill) { ctx.fillStyle=fill; ctx.fill(); }\n        if (stroke) { ctx.strokeStyle=stroke; ctx.stroke(); }\n      }\n\n      function drawStar(x,y,r,color,alpha,rotation) {\n        ctx.save();\n        ctx.globalAlpha = alpha == null ? 1 : alpha;\n        ctx.translate(x,y);\n        ctx.rotate(rotation || 0);\n        ctx.fillStyle = color || \"#fffaf0\";\n        ctx.beginPath();\n        for (let i=0;i<8;i++) {\n          const rr = i%2===0 ? r : r*.3;\n          const angle = -Math.PI\/2 + i*Math.PI\/4;\n          const px = Math.cos(angle)*rr;\n          const py = Math.sin(angle)*rr;\n          if (i===0) ctx.moveTo(px,py); else ctx.lineTo(px,py);\n        }\n        ctx.closePath();\n        ctx.fill();\n        ctx.restore();\n      }\n\n\n\n\n\n\n\n\n\n\nfunction drawMoonWorkshopBackground() {\n  const dark = darkTheme();\n  const sky = ctx.createLinearGradient(0, 0, 0, DESIGN_H);\n  sky.addColorStop(0, dark ? \"#171124\" : \"#2b1c48\");\n  sky.addColorStop(.55, dark ? \"#281b3a\" : \"#4a3268\");\n  sky.addColorStop(1, dark ? \"#3d2947\" : \"#6f4f78\");\n  ctx.fillStyle = sky;\n  ctx.fillRect(0, 0, DESIGN_W, DESIGN_H);\n\n  const moonGlow = ctx.createRadialGradient(1030, 126, 10, 1030, 126, 178);\n  moonGlow.addColorStop(0, \"rgba(255,244,207,.94)\");\n  moonGlow.addColorStop(.34, \"rgba(255,226,158,.50)\");\n  moonGlow.addColorStop(1, \"rgba(255,226,158,0)\");\n  ctx.fillStyle = moonGlow;\n  ctx.fillRect(830, -72, 400, 400);\n\n  ctx.fillStyle = \"#fff1c9\";\n  ctx.beginPath();\n  ctx.arc(1030, 126, 84, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.fillStyle = dark ? \"rgba(73,48,84,.25)\" : \"rgba(139,111,147,.18)\";\n  ctx.beginPath();\n  ctx.arc(1002, 98, 15, 0, Math.PI * 2);\n  ctx.arc(1064, 133, 19, 0, Math.PI * 2);\n  ctx.arc(1025, 166, 12, 0, Math.PI * 2);\n  ctx.fill();\n\n  const starShift = -((state.roadOffset * .018) % 230);\n  for (let i = -2; i < 12; i++) {\n    const x = starShift + i * 132 + 46;\n    const y = 78 + ((i * 67) % 260);\n    drawStar(x, y, 3 + (i % 3), i % 2 ? \"#fff1c9\" : \"#cfd1ff\", .72, state.elapsed * .22 + i);\n  }\n\n  drawCloudLayer(84, .16, dark ? \"#51406f\" : \"#8d79b0\", .44);\n  drawCloudLayer(190, .28, dark ? \"#3c3156\" : \"#725e97\", .72);\n\n  ctx.fillStyle = dark ? \"#2a1f35\" : \"#3a284a\";\n  ctx.fillRect(0, 0, DESIGN_W, 62);\n  ctx.fillStyle = dark ? \"#5f4265\" : \"#7b5236\";\n  ctx.fillRect(0, 54, DESIGN_W, 12);\n\n  for (let i = 0; i < 7; i++) {\n    const x = 80 + i * 188;\n    ctx.strokeStyle = \"rgba(255,241,201,.42)\";\n    ctx.lineWidth = 2;\n    ctx.beginPath();\n    ctx.moveTo(x, 62);\n    ctx.lineTo(x, 112 + (i % 2) * 20);\n    ctx.stroke();\n\n    const glow = ctx.createRadialGradient(x, 118 + (i % 2) * 20, 2, x, 118 + (i % 2) * 20, 34);\n    glow.addColorStop(0, \"rgba(255,241,201,.94)\");\n    glow.addColorStop(1, \"rgba(244,197,66,0)\");\n    ctx.fillStyle = glow;\n    ctx.beginPath();\n    ctx.arc(x, 118 + (i % 2) * 20, 34, 0, Math.PI * 2);\n    ctx.fill();\n\n    roundedRect(x - 13, 102 + (i % 2) * 20, 26, 30, 8, \"#f4c542\", \"#7b5236\");\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.beginPath();\n    ctx.arc(x, 117 + (i % 2) * 20, 6, 0, Math.PI * 2);\n    ctx.fill();\n  }\n\n  roundedRect(26, 304, 248, 182, 20, dark ? \"#2d2037\" : \"#493251\", dark ? \"#7f5e7f\" : \"#7b5236\");\n  roundedRect(1004, 304, 248, 182, 20, dark ? \"#2d2037\" : \"#493251\", dark ? \"#7f5e7f\" : \"#7b5236\");\n\n  drawWorkshopShelf(44, 330, 210, 132);\n  drawWorkshopShelf(1022, 330, 210, 132);\n\n  const vignette = ctx.createRadialGradient(DESIGN_W \/ 2, 330, 250, DESIGN_W \/ 2, 330, 820);\n  vignette.addColorStop(0, \"rgba(20,12,29,0)\");\n  vignette.addColorStop(1, dark ? \"rgba(7,5,12,.42)\" : \"rgba(26,16,38,.22)\");\n  ctx.fillStyle = vignette;\n  ctx.fillRect(0, 0, DESIGN_W, DESIGN_H);\n\n  function drawCloudLayer(baseY, speedFactor, color, alpha) {\n    const shift = -((state.roadOffset * speedFactor) % 280);\n    ctx.save();\n    ctx.globalAlpha = alpha;\n    ctx.fillStyle = color;\n    for (let i = -2; i < 8; i++) {\n      const x = shift + i * 230;\n      ctx.beginPath();\n      ctx.ellipse(x + 70, baseY + 70, 98, 38, 0, 0, Math.PI * 2);\n      ctx.ellipse(x + 138, baseY + 50, 82, 48, 0, 0, Math.PI * 2);\n      ctx.ellipse(x + 196, baseY + 72, 94, 35, 0, 0, Math.PI * 2);\n      ctx.fill();\n    }\n    ctx.restore();\n  }\n\n  function drawWorkshopShelf(x, y, w, h) {\n    ctx.fillStyle = dark ? \"#553a2d\" : \"#7b5236\";\n    ctx.fillRect(x, y, w, 12);\n    ctx.fillRect(x, y + h - 12, w, 12);\n    ctx.fillRect(x, y, 12, h);\n    ctx.fillRect(x + w - 12, y, 12, h);\n    ctx.fillRect(x, y + 58, w, 9);\n\n    for (let i = 0; i < 5; i++) {\n      const bx = x + 24 + i * 37;\n      roundedRect(bx, y + 20, 25, 28, 7, i % 2 ? \"#8b78b8\" : \"#d9a95b\", \"#3a284a\");\n      ctx.fillStyle = \"#fff1c9\";\n      ctx.beginPath();\n      ctx.arc(bx + 12.5, y + 34, 5, 0, Math.PI * 2);\n      ctx.fill();\n    }\n\n    for (let i = 0; i < 4; i++) {\n      const tx = x + 26 + i * 46;\n      ctx.strokeStyle = \"#d9a95b\";\n      ctx.lineWidth = 5;\n      ctx.beginPath();\n      ctx.moveTo(tx, y + 80);\n      ctx.lineTo(tx + 18, y + 112);\n      ctx.stroke();\n      ctx.fillStyle = \"#7b5236\";\n      roundedRect(tx - 6, y + 72, 22, 14, 6, \"#7b5236\", \"#f4c542\");\n    }\n  }\n}\n\n\nfunction drawMoonworkBench() {\n  const dark = darkTheme();\n  const bench = ctx.createLinearGradient(0, GROUND_Y - 62, 0, DESIGN_H);\n  bench.addColorStop(0, dark ? \"#7a523f\" : \"#9a6849\");\n  bench.addColorStop(.48, dark ? \"#5f3d30\" : \"#7b5236\");\n  bench.addColorStop(1, dark ? \"#37251f\" : \"#4d3126\");\n  ctx.fillStyle = bench;\n  ctx.fillRect(0, GROUND_Y - 62, DESIGN_W, DESIGN_H - GROUND_Y + 62);\n\n  ctx.fillStyle = \"#d9a95b\";\n  ctx.fillRect(0, GROUND_Y - 6, DESIGN_W, 8);\n  ctx.fillStyle = \"rgba(255,241,201,.55)\";\n  ctx.fillRect(0, GROUND_Y - 10, DESIGN_W, 2);\n\n  const seamOffset = -((state.roadOffset * .56) % 220);\n  ctx.strokeStyle = dark ? \"rgba(255,241,201,.13)\" : \"rgba(255,241,201,.25)\";\n  ctx.lineWidth = 3;\n  for (let i = -2; i < 10; i++) {\n    const x = seamOffset + i * 220;\n    ctx.beginPath();\n    ctx.moveTo(x, GROUND_Y + 3);\n    ctx.lineTo(x + 44, DESIGN_H);\n    ctx.stroke();\n  }\n\n  const stampOffset = -((state.roadOffset * .74) % 132);\n  for (let i = -2; i < 13; i++) {\n    const x = stampOffset + i * 132 + 44;\n    drawMoonStamp(x, GROUND_Y + 82, 13);\n  }\n\n  ctx.fillStyle = dark ? \"rgba(16,10,20,.48)\" : \"rgba(34,20,40,.24)\";\n  ctx.fillRect(0, DESIGN_H - 28, DESIGN_W, 28);\n\n  function drawMoonStamp(x, y, r) {\n    ctx.save();\n    ctx.globalAlpha = .34;\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.beginPath();\n    ctx.arc(x, y, r, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.fillStyle = dark ? \"#5f3d30\" : \"#7b5236\";\n    ctx.beginPath();\n    ctx.arc(x + r * .45, y - r * .18, r * .85, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.restore();\n  }\n}\n\n\nfunction drawPlayer() {\n  const p = world.player;\n  if (!p) return;\n\n  const run = Math.sin(p.phase * 6.3);\n  const bob = Math.cos(p.phase * 6.3);\n  const airborne = !p.grounded;\n  const bodyBob = (p.grounded ? !p.ducking : false) ? bob * 3 : (airborne ? -2 : 0);\n  const tilt = p.ducking ? -.18 : airborne ? clamp(-p.vy \/ 820, -1, 1) * .10 : run * .035;\n\n  ctx.save();\n  ctx.translate(p.x + p.w * .5, p.y + bodyBob);\n  ctx.rotate(tilt);\n  ctx.translate(-p.w * .5, 0);\n\n  if (state.mochiShieldTimer > 0 ? state.mochiShieldHits > 0 : false) {\n    const shield = ctx.createRadialGradient(p.w * .5, p.h * .5, 8, p.w * .5, p.h * .5, p.w);\n    shield.addColorStop(0, \"rgba(255,241,201,.12)\");\n    shield.addColorStop(.52, \"rgba(207,209,255,.38)\");\n    shield.addColorStop(1, \"rgba(139,120,184,0)\");\n    ctx.fillStyle = shield;\n    ctx.strokeStyle = \"rgba(255,241,201,.96)\";\n    ctx.lineWidth = 3;\n    ctx.beginPath();\n    ctx.ellipse(p.w * .5, p.h * .52, p.w * .91, p.h * .80, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n    drawStar(p.w * .84, p.h * .20, 7, \"#f4c542\", .96, p.phase);\n  }\n\n  if (p.grounded) {\n    ctx.fillStyle = \"rgba(20,12,28,.28)\";\n    ctx.beginPath();\n    ctx.ellipse(p.w * .5, p.h * 1.01, p.w * (p.ducking ? .63 : .49), p.h * .065, 0, 0, Math.PI * 2);\n    ctx.fill();\n  }\n\n  ctx.fillStyle = \"#fff8e7\";\n  ctx.strokeStyle = \"#6b4a65\";\n  ctx.lineWidth = 3;\n\n  ctx.save();\n  ctx.translate(p.w * .17, p.h * .61);\n  ctx.beginPath();\n  ctx.arc(0, 0, p.w * .14, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.stroke();\n  ctx.restore();\n\n  ctx.strokeStyle = \"#7b5236\";\n  ctx.lineWidth = 7;\n  ctx.lineCap = \"round\";\n  ctx.beginPath();\n  if (p.ducking) {\n    ctx.moveTo(p.w * .38, p.h * .79);\n    ctx.lineTo(p.w * .14, p.h * .84);\n    ctx.moveTo(p.w * .63, p.h * .79);\n    ctx.lineTo(p.w * .88, p.h * .84);\n  } else {\n    ctx.moveTo(p.w * .40, p.h * .78);\n    ctx.lineTo(p.w * (.26 + run * .08), p.h * .94);\n    ctx.moveTo(p.w * .60, p.h * .78);\n    ctx.lineTo(p.w * (.74 - run * .08), p.h * .94);\n  }\n  ctx.stroke();\n  roundedRect(p.w * .03, p.h * .91, p.w * .38, p.h * .075, 7, \"#39244d\", \"#d9a95b\");\n  roundedRect(p.w * .59, p.h * .91, p.w * .38, p.h * .075, 7, \"#39244d\", \"#d9a95b\");\n\n  const body = ctx.createRadialGradient(p.w * .42, p.h * .44, 4, p.w * .5, p.h * .54, p.w * .40);\n  body.addColorStop(0, \"#fffdf5\");\n  body.addColorStop(.58, \"#f7eadf\");\n  body.addColorStop(1, \"#d9c6c4\");\n  ctx.fillStyle = body;\n  ctx.strokeStyle = \"#6b4a65\";\n  ctx.lineWidth = 4;\n  ctx.beginPath();\n  ctx.ellipse(p.w * .5, p.h * .57, p.w * .35, p.h * .31, 0, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.stroke();\n\n  ctx.fillStyle = \"#57406e\";\n  ctx.strokeStyle = \"#39244d\";\n  ctx.lineWidth = 3;\n  ctx.beginPath();\n  ctx.moveTo(p.w * .32, p.h * .42);\n  ctx.lineTo(p.w * .68, p.h * .42);\n  ctx.lineTo(p.w * .74, p.h * .79);\n  ctx.lineTo(p.w * .26, p.h * .79);\n  ctx.closePath();\n  ctx.fill();\n  ctx.stroke();\n\n  roundedRect(p.w * .39, p.h * .59, p.w * .23, p.h * .12, 6, \"#fff1c9\", \"#d9a95b\");\n  ctx.fillStyle = \"#f4c542\";\n  ctx.beginPath();\n  ctx.arc(p.w * .505, p.h * .65, 4, 0, Math.PI * 2);\n  ctx.fill();\n\n  roundedRect(p.w * .64, p.h * .50, p.w * .27, p.h * .28, 10, \"#7b5236\", \"#d9a95b\");\n  ctx.fillStyle = \"#fff1c9\";\n  ctx.beginPath();\n  ctx.arc(p.w * .775, p.h * .62, 6, 0, Math.PI * 2);\n  ctx.fill();\n\n  ctx.fillStyle = \"#fff8e7\";\n  ctx.strokeStyle = \"#6b4a65\";\n  ctx.lineWidth = 3;\n  ctx.beginPath();\n  ctx.ellipse(p.w * .37, p.h * .04, p.w * .105, p.h * .26, -.12, 0, Math.PI * 2);\n  ctx.ellipse(p.w * .63, p.h * .04, p.w * .105, p.h * .26, .12, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.stroke();\n\n  ctx.fillStyle = \"#e7a9ae\";\n  ctx.beginPath();\n  ctx.ellipse(p.w * .37, p.h * .04, p.w * .045, p.h * .17, -.12, 0, Math.PI * 2);\n  ctx.ellipse(p.w * .63, p.h * .04, p.w * .045, p.h * .17, .12, 0, Math.PI * 2);\n  ctx.fill();\n\n  ctx.fillStyle = \"#fff8e7\";\n  ctx.strokeStyle = \"#6b4a65\";\n  ctx.beginPath();\n  ctx.ellipse(p.w * .5, p.h * .27, p.w * .24, p.h * .21, 0, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.stroke();\n\n  ctx.fillStyle = \"#23142f\";\n  ctx.beginPath();\n  ctx.arc(p.w * .43, p.h * .24, 4, 0, Math.PI * 2);\n  ctx.arc(p.w * .57, p.h * .24, 4, 0, Math.PI * 2);\n  ctx.fill();\n\n  ctx.fillStyle = \"#d96f6f\";\n  ctx.beginPath();\n  ctx.arc(p.w * .50, p.h * .30, 3.5, 0, Math.PI * 2);\n  ctx.fill();\n\n  ctx.strokeStyle = \"#7b5236\";\n  ctx.lineWidth = 1.6;\n  ctx.beginPath();\n  ctx.arc(p.w * .50, p.h * .32, 6, .1, Math.PI - .1);\n  ctx.stroke();\n\n  ctx.fillStyle = \"#8b78b8\";\n  ctx.beginPath();\n  ctx.moveTo(p.w * .31, p.h * .38);\n  ctx.lineTo(p.w * .69, p.h * .38);\n  ctx.lineTo(p.w * .62, p.h * .47);\n  ctx.lineTo(p.w * .38, p.h * .47);\n  ctx.closePath();\n  ctx.fill();\n\n  ctx.strokeStyle = \"#fff1c9\";\n  ctx.lineWidth = 5;\n  ctx.beginPath();\n  ctx.moveTo(p.w * .31, p.h * .46);\n  ctx.lineTo(p.w * (.08 + run * .04), p.h * .59);\n  ctx.moveTo(p.w * .69, p.h * .46);\n  ctx.lineTo(p.w * (.92 - run * .04), p.h * .55);\n  ctx.stroke();\n\n  if (state.cloudSpringTimer > 0) {\n    ctx.strokeStyle = \"rgba(207,209,255,.96)\";\n    ctx.lineWidth = 3;\n    for (let i = 0; i < 3; i++) {\n      ctx.beginPath();\n      ctx.moveTo(p.w * (.20 + i * .20), p.h * .89);\n      ctx.bezierCurveTo(p.w * (.09 + i * .20), p.h * .73, p.w * (.26 + i * .20), p.h * .58, p.w * (.15 + i * .20), p.h * .43);\n      ctx.stroke();\n    }\n  }\n\n  ctx.restore();\n}\n\n\nfunction drawMochiCrates(o) {\n  ctx.save();\n  ctx.translate(o.x, o.y);\n  ctx.fillStyle = \"rgba(20,12,28,.24)\";\n  ctx.beginPath();\n  ctx.ellipse(o.w * .5, o.h * 1.03, o.w * .49, o.h * .09, 0, 0, Math.PI * 2);\n  ctx.fill();\n\n  roundedRect(o.w * .03, o.h * .42, o.w * .94, o.h * .48, 13, \"#7b5236\", \"#4d3126\");\n  ctx.strokeStyle = \"rgba(255,241,201,.38)\";\n  ctx.lineWidth = 3;\n  for (let i = 1; i < 4; i++) {\n    ctx.beginPath();\n    ctx.moveTo(o.w * (.03 + i * .235), o.h * .46);\n    ctx.lineTo(o.w * (.03 + i * .235), o.h * .86);\n    ctx.stroke();\n  }\n\n  const mochis = [\n    {x:.11,y:.19,r:.18,c:\"#fff1c9\"},\n    {x:.38,y:.08,r:.20,c:\"#e9b8c0\"},\n    {x:.67,y:.18,r:.17,c:\"#cfd1ff\"}\n  ];\n  mochis.forEach(function(m) {\n    ctx.fillStyle = m.c;\n    ctx.strokeStyle = \"#8b6c78\";\n    ctx.lineWidth = 3;\n    ctx.beginPath();\n    ctx.ellipse(o.w * (m.x + m.r), o.h * (m.y + m.r), o.w * m.r, o.h * m.r * .72, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n    ctx.fillStyle = \"#f4c542\";\n    ctx.beginPath();\n    ctx.arc(o.w * (m.x + m.r), o.h * (m.y + m.r * .58), 4, 0, Math.PI * 2);\n    ctx.fill();\n  });\n  ctx.restore();\n}\n\n\nfunction drawToolboxes(o) {\n  ctx.save();\n  ctx.translate(o.x, o.y);\n  ctx.fillStyle = \"rgba(20,12,28,.24)\";\n  ctx.beginPath();\n  ctx.ellipse(o.w * .5, o.h * 1.03, o.w * .49, o.h * .09, 0, 0, Math.PI * 2);\n  ctx.fill();\n\n  roundedRect(o.w * .06, o.h * .30, o.w * .88, o.h * .60, 14, \"#9a6849\", \"#4d3126\");\n  ctx.fillStyle = \"#d9a95b\";\n  ctx.fillRect(o.w * .08, o.h * .52, o.w * .84, o.h * .08);\n  roundedRect(o.w * .27, o.h * .12, o.w * .46, o.h * .24, 12, \"rgba(0,0,0,0)\", \"#d9a95b\");\n\n  for (let i = 0; i < 3; i++) {\n    const x = o.w * (.24 + i * .26);\n    ctx.strokeStyle = i === 1 ? \"#cfd1ff\" : \"#fff1c9\";\n    ctx.lineWidth = 6;\n    ctx.beginPath();\n    ctx.moveTo(x, o.h * .45);\n    ctx.lineTo(x + o.w * .08, o.h * .77);\n    ctx.stroke();\n    roundedRect(x - o.w * .03, o.h * .36, o.w * .17, o.h * .14, 6, \"#7b5236\", \"#f4c542\");\n  }\n  ctx.restore();\n}\n\n\nfunction drawLanternCart(o) {\n  ctx.save();\n  ctx.translate(o.x, o.y);\n  ctx.fillStyle = \"rgba(20,12,28,.24)\";\n  ctx.beginPath();\n  ctx.ellipse(o.w * .5, o.h * 1.04, o.w * .49, o.h * .09, 0, 0, Math.PI * 2);\n  ctx.fill();\n\n  roundedRect(o.w * .05, o.h * .42, o.w * .90, o.h * .34, 12, \"#7b5236\", \"#4d3126\");\n  ctx.fillStyle = \"#8b78b8\";\n  ctx.fillRect(o.w * .08, o.h * .34, o.w * .84, o.h * .12);\n\n  for (let i = 0; i < 4; i++) {\n    const x = o.w * (.13 + i * .21);\n    const y = o.h * (.10 + (i % 2) * .04);\n    const glow = ctx.createRadialGradient(x + o.w * .07, y + o.h * .14, 2, x + o.w * .07, y + o.h * .14, o.h * .28);\n    glow.addColorStop(0, \"rgba(255,241,201,.92)\");\n    glow.addColorStop(1, \"rgba(244,197,66,0)\");\n    ctx.fillStyle = glow;\n    ctx.fillRect(x - 24, y - 18, 66, 66);\n    roundedRect(x, y, o.w * .14, o.h * .27, 9, \"#f4c542\", \"#7b5236\");\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.beginPath();\n    ctx.arc(x + o.w * .07, y + o.h * .14, 5, 0, Math.PI * 2);\n    ctx.fill();\n  }\n\n  ctx.fillStyle = \"#23142f\";\n  ctx.beginPath();\n  ctx.arc(o.w * .24, o.h * .84, o.h * .12, 0, Math.PI * 2);\n  ctx.arc(o.w * .76, o.h * .84, o.h * .12, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.strokeStyle = \"#d9a95b\";\n  ctx.lineWidth = 4;\n  ctx.stroke();\n  ctx.restore();\n}\n\n\nfunction drawMalletRack(o) {\n  ctx.save();\n  ctx.translate(o.x, o.y);\n  const lower = o.h;\n  const sway = Math.sin(performance.now() * .0017 + o.phase) * 3;\n\n  ctx.fillStyle = \"#39244d\";\n  ctx.fillRect(0, 0, o.w, 18);\n  ctx.fillStyle = \"#7b5236\";\n  ctx.fillRect(o.w * .07, 0, 12, lower - 84);\n  ctx.fillRect(o.w * .87, 0, 12, lower - 84);\n  roundedRect(o.w * .03, lower - 106, o.w * .94, 54, 12, \"#7b5236\", \"#d9a95b\");\n\n  for (let i = 0; i < 5; i++) {\n    const x = o.w * (.13 + i * .18);\n    ctx.strokeStyle = \"rgba(255,241,201,.68)\";\n    ctx.lineWidth = 2;\n    ctx.beginPath();\n    ctx.moveTo(x, lower - 52);\n    ctx.lineTo(x + sway * (i % 2 ? 1 : -1), lower - 10);\n    ctx.stroke();\n\n    ctx.strokeStyle = \"#d9a95b\";\n    ctx.lineWidth = 6;\n    ctx.beginPath();\n    ctx.moveTo(x - 2, lower - 44);\n    ctx.lineTo(x + 12, lower - 12);\n    ctx.stroke();\n    roundedRect(x - 12, lower - 54, 28, 16, 6, \"#7b5236\", \"#f4c542\");\n  }\n  ctx.restore();\n}\n\nfunction drawMoonclothBanners(o) {\n  ctx.save();\n  ctx.translate(o.x, o.y);\n  const lower = o.h;\n  const sway = Math.sin(performance.now() * .0015 + o.phase) * 3;\n\n  ctx.fillStyle = \"#39244d\";\n  ctx.fillRect(0, 0, o.w, 18);\n  ctx.fillStyle = \"#7b5236\";\n  ctx.fillRect(o.w * .06, 0, 11, lower - 94);\n  ctx.fillRect(o.w * .89, 0, 11, lower - 94);\n\n  ctx.strokeStyle = \"#d9a95b\";\n  ctx.lineWidth = 7;\n  ctx.beginPath();\n  ctx.moveTo(o.w * .05, lower - 101);\n  ctx.quadraticCurveTo(o.w * .50, lower - 116, o.w * .95, lower - 101);\n  ctx.stroke();\n\n  const cloths = [\n    {x:.08,w:.24,c:\"#cfd1ff\"},\n    {x:.38,w:.24,c:\"#8b78b8\"},\n    {x:.68,w:.23,c:\"#57406e\"}\n  ];\n\n  cloths.forEach(function(cloth, index) {\n    const x = o.w * cloth.x + sway * (index - 1);\n    const y = lower - 98;\n    const w = o.w * cloth.w;\n    const h = 86 + (index % 2) * 12;\n    roundedRect(x, y, w, h, 8, cloth.c, \"rgba(57,36,77,.55)\");\n\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.beginPath();\n    ctx.arc(x + w * .50, y + h * .42, w * .17, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.fillStyle = cloth.c;\n    ctx.beginPath();\n    ctx.arc(x + w * .60, y + h * .36, w * .16, 0, Math.PI * 2);\n    ctx.fill();\n  });\n  ctx.restore();\n}\n\n\nfunction drawObstacle(o) {\n  if (o.kind === \"mochiCrates\") drawMochiCrates(o);\n  else if (o.kind === \"toolboxes\") drawToolboxes(o);\n  else if (o.kind === \"lanternCart\") drawLanternCart(o);\n  else if (o.kind === \"malletRack\") drawMalletRack(o);\n  else drawMoonclothBanners(o);\n}\n\n\nfunction drawPickup(pickup) {\n  const y = pickup.y + Math.sin(pickup.bob) * 4;\n\n  if (pickup.type === \"moonCharm\") {\n    ctx.save();\n    const halo = ctx.createRadialGradient(pickup.x, y, 0, pickup.x, y, pickup.r * 2.8);\n    halo.addColorStop(0, \"rgba(255,241,201,.94)\");\n    halo.addColorStop(.42, \"rgba(244,197,66,.48)\");\n    halo.addColorStop(1, \"rgba(244,197,66,0)\");\n    ctx.fillStyle = halo;\n    ctx.beginPath();\n    ctx.arc(pickup.x, y, pickup.r * 2.8, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.translate(pickup.x, y);\n    ctx.rotate(Math.sin(pickup.spin * .12) * .12);\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.strokeStyle = \"#7b5236\";\n    ctx.lineWidth = 3;\n    ctx.beginPath();\n    ctx.arc(0, 0, pickup.r * .84, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n\n    ctx.fillStyle = \"#8b78b8\";\n    ctx.beginPath();\n    ctx.arc(-4, -8, 3.6, 0, Math.PI * 2);\n    ctx.arc(4, -8, 3.6, 0, Math.PI * 2);\n    ctx.arc(0, 0, 8, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = \"#f4c542\";\n    ctx.beginPath();\n    ctx.arc(0, 1, 3, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.restore();\n    drawStar(pickup.x - pickup.r, y - pickup.r * .82, pickup.r * .2, \"#cfd1ff\", .95, pickup.spin);\n    return;\n  }\n\n  ctx.save();\n  const halo = ctx.createRadialGradient(pickup.x, y, 0, pickup.x, y, pickup.r * 2.3);\n  halo.addColorStop(0, \"rgba(255,241,201,.88)\");\n  halo.addColorStop(.52, pickup.type === \"mochiShield\" ? \"rgba(231,169,174,.48)\" : \"rgba(207,209,255,.48)\");\n  halo.addColorStop(1, \"rgba(255,241,201,0)\");\n  ctx.fillStyle = halo;\n  ctx.beginPath();\n  ctx.arc(pickup.x, y, pickup.r * 2.3, 0, Math.PI * 2);\n  ctx.fill();\n  ctx.translate(pickup.x, y);\n\n  if (pickup.type === \"mochiShield\") {\n    ctx.fillStyle = \"#fff1c9\";\n    ctx.strokeStyle = \"#8b78b8\";\n    ctx.lineWidth = 4;\n    ctx.beginPath();\n    ctx.arc(0, 0, 24, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n    ctx.fillStyle = \"#e9b8c0\";\n    ctx.beginPath();\n    ctx.ellipse(0, 4, 14, 11, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.fillStyle = \"#d96f6f\";\n    ctx.beginPath();\n    ctx.arc(-5, 2, 2, 0, Math.PI * 2);\n    ctx.arc(5, 2, 2, 0, Math.PI * 2);\n    ctx.fill();\n  } else {\n    ctx.strokeStyle = \"#cfd1ff\";\n    ctx.lineWidth = 5;\n    for (let i = 0; i < 5; i++) {\n      const yy = -24 + i * 11;\n      ctx.beginPath();\n      ctx.moveTo(-20, yy);\n      ctx.bezierCurveTo(-7, yy - 10, 7, yy + 10, 20, yy);\n      ctx.stroke();\n    }\n    drawStar(0, 0, 10, \"#f4c542\", .95, pickup.spin * .2);\n  }\n\n  ctx.restore();\n}\n\n      function drawParticles() {\n        world.particles.forEach(function(p){\n          const alpha=clamp(p.life\/p.maxLife,0,1);\n          if(p.star)drawStar(p.x,p.y,p.size*alpha,p.color,alpha,p.life*7);\n          else{\n            ctx.globalAlpha=alpha;ctx.fillStyle=p.color;ctx.beginPath();ctx.arc(p.x,p.y,p.size*alpha,0,Math.PI*2);ctx.fill();ctx.globalAlpha=1;\n          }\n        });\n      }\n\n      function drawScene() {\n        const shakeX=state.shake>0?Math.sin(performance.now()*.05)*4*(state.shake\/.22):0;\n        const shakeY=state.shake>0?Math.cos(performance.now()*.04)*3*(state.shake\/.22):0;\n        ctx.save();\n        ctx.translate(shakeX,shakeY);\n        drawMoonWorkshopBackground();\n        drawMoonworkBench();\n        world.pickups.forEach(drawPickup);\n        world.obstacles.forEach(drawObstacle);\n        drawPlayer();\n        drawParticles();\n        ctx.restore();\n      }\n\n      function loop(timestamp) {\n        if (!root.isConnected) return;\n        if(!state.lastTime)state.lastTime=timestamp;\n        if (!gameInView || document.hidden) {\n          state.lastTime = timestamp;\n          requestAnimationFrame(loop);\n          return;\n        }\n        const dt=Math.min(.028,(timestamp-state.lastTime)\/1000);\n        state.lastTime=timestamp;\n        if(state.mode===\"playing\")update(dt);\n        else{\n          updateParticles(dt);\n          state.shake=Math.max(0,state.shake-dt);\n        }\n        ctx.clearRect(0,0,DESIGN_W,DESIGN_H);\n        drawScene();\n        requestAnimationFrame(loop);\n      }\n\n      function toggleMute() {\n        state.muted=!state.muted;\n        soundButton.classList.toggle(\"mmn-muted\",state.muted);\n        soundButton.setAttribute(\"aria-label\",state.muted?\"Unmute sound\":\"Mute sound\");\n        safeSet(MUTE_KEY,state.muted?\"1\":\"0\");\n        if(!state.muted)sound(\"click\");\n      }\n\n      function fullscreenElement() {\n        return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement;\n      }\n\n      function fullscreenActive() {\n        return fullscreenElement() === root || fallbackFullscreen;\n      }\n\n      function syncFullscreenMetrics() {\n        const active=fullscreenActive();\n        root.classList.toggle(\"mmn-fullscreen-active\", active);\n        const viewport=window.visualViewport;\n        const width=Math.max(1,viewport ? (viewport.width || window.innerWidth) : window.innerWidth);\n        const height=Math.max(1,viewport ? (viewport.height || window.innerHeight) : window.innerHeight);\n        const offsetLeft=viewport ? (Number.isFinite(viewport.offsetLeft) ? viewport.offsetLeft : 0) : 0;\n        const offsetTop=viewport ? (Number.isFinite(viewport.offsetTop) ? viewport.offsetTop : 0) : 0;\n        const shellW=Math.min(width,height*16\/9);\n        const shellH=Math.min(height,width*9\/16);\n        root.style.setProperty(\"--mmn-fs-shell-w\",shellW+\"px\");\n        root.style.setProperty(\"--mmn-fs-shell-h\",shellH+\"px\");\n        root.style.setProperty(\"--mmn-fs-center-x\",(offsetLeft+width\/2)+\"px\");\n        root.style.setProperty(\"--mmn-fs-center-y\",(offsetTop+height\/2)+\"px\");\n      }\n\n      async function toggleFullscreen() {\n        sound(\"click\");\n        if (!fullscreenActive()) {\n          try {\n            const request = root.requestFullscreen || root.webkitRequestFullscreen || root.mozRequestFullScreen || root.msRequestFullscreen;\n            if (request) {\n              await Promise.resolve(request.call(root));\n            } else {\n              fallbackFullscreen = true;\n            }\n            try {\n              if (screen.orientation ? (screen.orientation.lock ? window.innerWidth < window.innerHeight : false) : false) {\n                await screen.orientation.lock(\"landscape\");\n              }\n            } catch (error) {}\n          } catch (error) {\n            fallbackFullscreen = true;\n            noteEl.textContent = \"Browser fullscreen was unavailable, so the moon workshop opened in fitted fullscreen mode.\";\n            noteEl.classList.add(\"mmn-show\");\n            state.noteTimer = 2.4;\n          }\n        } else {\n          if (fullscreenElement() === root) {\n            try {\n              const exit = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen;\n              if (exit) await Promise.resolve(exit.call(document));\n            } catch (error) {}\n          }\n          fallbackFullscreen = false;\n          try { if (screen.orientation ? screen.orientation.unlock : false) screen.orientation.unlock(); } catch (error) {}\n        }\n        syncFullscreenMetrics();\n        requestAnimationFrame(resize);\n        setTimeout(function () { syncFullscreenMetrics(); resize(); }, 160);\n      }\n\n      function handleAction(action,event) {\n        if(event)event.preventDefault();\n        ensureAudio();\n        if(action===\"pause\"){\n          if(state.mode===\"playing\")pauseGame();\n          else if(state.mode===\"paused\")resumeGame();\n        }else if(action===\"sound\")toggleMute();\n        else if(action===\"fullscreen\")toggleFullscreen();\n        else if(action===\"main\"){\n          if(state.mode===\"paused\")resumeGame();else startGame();\n        }else if(action===\"restart\")startGame();\n        else if(action===\"jump\")jump();\n        else if(action===\"duck\")setDuck(true);\n      }\n\n      root.addEventListener(\"click\",function(event){\n        const button=event.target.closest(\"[data-mmn-action]\");\n        if(!button)return;\n        const action=button.dataset.mmnAction;\n        if(action===\"jump\"||action===\"duck\")return;\n        handleAction(action,event);\n      });\n\n      root.querySelectorAll('[data-mmn-action=\"jump\"]').forEach(function(button){\n        button.addEventListener(\"pointerdown\",function(event){handleAction(\"jump\",event);});\n        [\"pointerup\",\"pointercancel\",\"pointerleave\"].forEach(function(type){\n          button.addEventListener(type,function(event){event.preventDefault();input.jumpHeld=false;});\n        });\n      });\n\n      root.querySelectorAll('[data-mmn-action=\"duck\"]').forEach(function(button){\n        button.addEventListener(\"pointerdown\",function(event){\n          try { button.setPointerCapture(event.pointerId); } catch (error) {}\n          handleAction(\"duck\",event);\n        });\n        [\"pointerup\",\"pointercancel\",\"pointerleave\"].forEach(function(type){\n          button.addEventListener(type,function(event){event.preventDefault();setDuck(false);});\n        });\n      });\n\n      canvas.addEventListener(\"pointerdown\",function(event){\n        event.preventDefault();\n        canvas.focus({ preventScroll: true });\n        if(state.mode===\"playing\")jump();\n      });\n\n      document.addEventListener(\"keydown\",function(event){\n        if (!gameInView || document.hidden || !root.contains(document.activeElement) || event.altKey || event.ctrlKey || event.metaKey) return;\n        const key=event.key;\n        if([\" \",\"ArrowUp\",\"ArrowDown\",\"w\",\"W\",\"s\",\"S\"].includes(key))event.preventDefault();\n        if(key===\" \"||key===\"ArrowUp\"||key===\"w\"||key===\"W\"){\n          if(!input.jumpHeld){input.jumpHeld=true;jump();}\n        }else if(key===\"ArrowDown\"||key===\"s\"||key===\"S\"){\n          if(!input.duckHeld)setDuck(true);\n        }else if(key===\"p\"||key===\"P\"){\n          if(state.mode===\"playing\")pauseGame();else if(state.mode===\"paused\")resumeGame();\n        }else if(key===\"m\"||key===\"M\")toggleMute();\n        else if(key===\"f\"||key===\"F\")toggleFullscreen();\n      });\n\n      root.addEventListener(\"focusout\", function(event) {\n        if (!root.contains(event.relatedTarget)) {\n          input.jumpHeld = false;\n          setDuck(false);\n        }\n      });\n      document.addEventListener(\"keyup\",function(event){\n        const key=event.key;\n        if(key===\" \"||key===\"ArrowUp\"||key===\"w\"||key===\"W\")input.jumpHeld=false;\n        else if(key===\"ArrowDown\"||key===\"s\"||key===\"S\")setDuck(false);\n      });\n\n      \n      document.addEventListener(\"keydown\", function (event) {\n        if (event.key === \"Escape\" ? fallbackFullscreen : false) {\n          fallbackFullscreen = false;\n          syncFullscreenMetrics();\n          resize();\n        }\n      });\n\n      function fullscreenChanged() {\n        syncFullscreenMetrics();\n        scheduleResize(80);\n        scheduleResize(260);\n      }\n\n      document.addEventListener(\"fullscreenchange\",fullscreenChanged);\n      document.addEventListener(\"webkitfullscreenchange\",fullscreenChanged);\n      document.addEventListener(\"mozfullscreenchange\",fullscreenChanged);\n      window.addEventListener(\"resize\",function(){scheduleResize(60);});\n      window.addEventListener(\"orientationchange\",function(){scheduleResize(180);});\n      if(window.visualViewport)window.visualViewport.addEventListener(\"resize\",function(){scheduleResize(70);});\n      if(typeof ResizeObserver!==\"undefined\"){\n        const observer=new ResizeObserver(function(){scheduleResize(40);});\n        observer.observe(frame);\n      }\n\n      soundButton.classList.toggle(\"mmn-muted\",state.muted);\n      soundButton.setAttribute(\"aria-label\",state.muted?\"Unmute sound\":\"Mute sound\");\n      world.player=createPlayer();\n      updateHud();\n      resize();\n      setMode(\"start\");\n      requestAnimationFrame(loop);\n    }\n      if (document.readyState === \"loading\") {\n        document.addEventListener(\"DOMContentLoaded\", initializeMochimallet, { once: true });\n      } else {\n        initializeMochimallet();\n      }\n    })();\n<\/script>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Run Through a Living Moonlit Workshop<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The running path in Mochimallet Nightdash is not an empty road. It is an active workbench filled with tools, materials, half-finished projects, and moving equipment. Each obstacle is connected to the world of the Moon Rabbit Workshop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mochi Crates sit directly on the route and must be jumped over. Toolboxes create solid barriers filled with carving tools, brushes, thread, and small wooden parts. Lantern Carts roll along the workbench carrying freshly repaired lights. These ground obstacles test the player\u2019s jumping timing and become harder to avoid as the running speed increases.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Other obstacles hang from the upper structure of the workshop. Mallet Racks extend down from ceiling beams, leaving only a low passage beneath them. Mooncloth Banners drift across the upper route and force Nori to duck close to the wooden surface. These obstacles are designed so players cannot simply jump over everything. They must recognize the difference between a ground barrier and an overhead hazard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The changing combination of jumping and ducking creates a varied rhythm. A tall toolbox may be followed by a low banner, requiring the player to land and immediately crouch. A hanging rack may appear before a trail of collectibles, encouraging careful positioning instead of random movement.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Jumping and Ducking<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nori runs automatically, allowing players to focus entirely on movement decisions. Desktop players can jump using the Space key, W, or the Up Arrow. Ducking is controlled with S or the Down Arrow. Mobile players can use the large Jump and Duck buttons positioned near the lower corners of the game screen.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A normal jump is used to clear objects placed on the workbench. Holding the jump control briefly can influence the movement and help Nori reach a higher arc. Releasing at the correct moment allows the rabbit to land safely before the next obstacle.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ducking works while Nori is running on the ground. The rabbit lowers its body and slides beneath hanging tools or cloth. Ducking at the wrong time can make it harder to prepare for an upcoming jump, so the player must return to a normal running position as soon as the upper obstacle has passed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The controls are easy to learn, but the increasing speed makes accurate timing essential. The most successful runs come from observing the route ahead and preparing before each obstacle reaches Nori.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Collecting Moon Charms<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Moon Charms appear in glowing trails throughout the workshop. These small circular tokens contain carefully stored lunar energy and are used to power lanterns, repair celestial tools, and mark completed deliveries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Collecting a Moon Charm increases the score and creates a brief burst of light around Nori. The charms are often arranged in curved patterns that encourage players to jump at a specific moment. Some trails appear after obstacles, rewarding a clean landing, while others float above dangerous objects and invite players to take a more precise route.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Within the story, every recovered charm helps the workshop recover from the cloudstorm. The more charms Nori collects, the more lanterns can be relit before morning. They are therefore both valuable gameplay collectibles and an important part of the courier\u2019s mission.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Mochi Moon Shield<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The Mochi Moon Shield is a rare protective power-up shaped from concentrated moonlight and soft rice dough. When collected, it surrounds Nori with a glowing barrier and allows the rabbit to survive one collision.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If Nori touches an obstacle while protected, the shield breaks instead of ending the run. The dangerous object is cleared from the immediate path, a burst of moonlit particles appears, and the courier continues forward.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The shield lasts for a limited period and can absorb only one impact. It is most useful during faster sections of the route, where obstacles approach quickly and a small timing error could otherwise end a strong run.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Players should not treat the shield as permission to stop paying attention. It is an emergency safeguard, and preserving it for a difficult combination of obstacles may be more valuable than using it immediately.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Cloudspring Power<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloudspring grants Nori one additional jump while already in the air. When the effect is active, the rabbit can jump from a cloudlike burst of energy and rise again before touching the ground.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This double-jump ability can help Nori clear unusually demanding ground obstacles, reach higher Moon Charm trails, or recover from a jump that was activated too early. It also gives players more freedom to explore different routes through collectible patterns.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The power lasts for a limited time, and the extra jump can be used only once during each airborne movement. Nori must touch the ground before another double jump becomes available.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Using Cloudspring carelessly can still create danger. Jumping too high may make it difficult to descend before an overhead Mallet Rack or Mooncloth Banner. The best use of the power depends on the obstacles visible ahead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Route That Becomes Faster<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mochimallet Nightdash begins at a comfortable speed so players can learn the controls and understand the obstacle shapes. As the run continues, the workshop counter moves faster and the time available to react becomes shorter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game introduces its hazards gradually. Basic Mochi Crates and Toolboxes appear early, followed by larger Lantern Carts. Overhead Mallet Racks and Mooncloth Banners enter the route after the player has gained some experience.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This progression prevents the beginning from feeling unfair while ensuring that long runs remain challenging. The controls never change, but the player must perform the same actions with increasing precision.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Obstacle spacing contains natural variation. Some sections provide a short breathing space, while others create demanding combinations. The game avoids relying on one repeated pattern, making each attempt feel slightly different.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Score, Milestones, and Best Records<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The score increases continuously as Nori travels through the workshop. Moon Charms and power-ups provide additional points, rewarding players who take active routes instead of simply avoiding hazards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every major score milestone is celebrated with a special sound and a burst of particles. These moments mark the distance Nori has travelled and give longer runs a sense of progress even though the route has no fixed ending.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game also stores the best score in the browser. When a run ends, players can immediately compare the result with their previous record and begin another attempt. The best-score system creates a personal challenge without requiring an account, online leaderboard, or complicated progression menu.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the route becomes faster over time, improving a record requires more than memorizing the controls. Players must develop better timing, recognize obstacles more quickly, and make smarter decisions about power-ups.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Cozy World with Energetic Gameplay<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The visual style of Mochimallet Nightdash combines the energy of an endless runner with the warmth of a handmade fantasy workshop. Deep plum skies and dusty lavender clouds surround warm wooden platforms. Creamy moonlight shines through round windows, while tiny lanterns illuminate shelves filled with tools and mochi-making equipment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nori\u2019s design reflects the workshop setting. The rabbit wears practical crafting clothes and carries a small pouch for collected charms. Every jump, landing, shield impact, and power-up creates small visual effects that make movement feel lively without covering the important gameplay area.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The background contains workshop details, but the obstacle silhouettes remain clear. Ground hazards are visually connected to the lower surface, while ducking obstacles hang down from the upper structure. This allows players to understand the required action quickly, even when the game reaches a high speed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Responsive Play on Desktop and Mobile<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mochimallet Nightdash is designed for modern desktop and mobile browsers. Its sixteen-by-nine landscape layout provides enough horizontal space to see approaching obstacles while keeping Nori and the controls clearly visible.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game supports keyboard controls, mouse or canvas input, and large touchscreen buttons. Pause and sound controls are placed in the upper-left corner, while fullscreen is positioned in the upper-right corner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fullscreen mode keeps the entire game centered and scales it according to both the available width and height. If a browser cannot lock the device into landscape orientation, the game still fits within the visible screen. The fullscreen button remains accessible while the start, pause, and game-over popup is displayed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sound effects are enabled by default and provide feedback for jumping, ducking, collecting charms, activating powers, breaking a shield, reaching milestones, and colliding with an obstacle. Players can mute the game at any time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Courage of a Small Apprentice<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Behind the running challenge is a story about accepting responsibility before feeling completely ready. Nori is not the strongest or most experienced courier in the Moon Rabbit Workshop. The young apprentice succeeds by paying attention, learning from mistakes, and continuing forward through an uncertain route.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each obstacle represents part of the workshop\u2019s disorder after the storm. Each recovered Moon Charm brings a small piece of light back home. The Mochi Moon Shield represents protection offered by the community, while Cloudspring represents the courage to try again before falling.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The route has no final gate because the workshop\u2019s work never truly ends. There will always be another lantern to repair, another cloud bridge to secure, and another charm that has drifted out of place. What matters is how far Nori can travel before returning to prepare for the next attempt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run across the moonwood counter, leap over scattered supplies, duck beneath swinging workshop equipment, collect the lost Moon Charms, and help Nori carry the Moon Rabbit Workshop\u2019s light safely through the night.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mochimallet Nightdash is a fast-paced endless runner set inside the Moon Rabbit Workshop, a magical crafting station suspended above the sleeping world. Players guide Nori, a young moon rabbit apprentice, across a moving wooden workbench filled with mochi crates, toolboxes, lantern carts, hanging mallets, and drifting workshop cloth. The objective is to run as far &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-87","post","type-post","status-publish","format-standard","hentry","category-casual"],"_links":{"self":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/posts\/87","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=87"}],"version-history":[{"count":0,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/posts\/87\/revisions"}],"wp:attachment":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=87"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=87"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=87"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}