{"id":78,"date":"2026-10-18T23:17:15","date_gmt":"2026-10-18T23:17:15","guid":{"rendered":"https:\/\/apk.produsenpagarbrc.com\/?p=78"},"modified":"2026-10-18T23:17:15","modified_gmt":"2026-10-18T23:17:15","slug":"mochiwing-moonflight","status":"publish","type":"post","link":"https:\/\/play.produsenpagarbrc.com\/?p=78","title":{"rendered":"Mochiwing Moonflight"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Mochiwing Moonflight is a cozy endless flying game set high above the sleeping world, where moonlit clouds drift around a secret workshop operated by tiny celestial rabbits. In this magical place, every lantern, charm, wooden tool, and piece of mochi is carefully crafted to keep the night sky glowing. Players guide a young moon rabbit courier through narrow workshop passages while collecting Moon Charms, avoiding hanging tool racks, and carrying precious supplies across the clouds.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game combines simple one-touch controls with a gradually increasing challenge. A single tap, click, or keyboard press lifts the courier upward, while gravity gently pulls the character back down. The objective is easy to understand but difficult to master: fly through every opening, maintain a steady rhythm, collect valuable charms, and travel as far as possible without touching the obstacles surrounding the route.<\/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\/Mochiwing-Moonflight-1024x768.png\" alt=\"\" class=\"wp-image-80\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">The Hidden Workshop Above the Clouds<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Long before people began counting the stars, the Moon Rabbit Workshop was built on the quietest layer of the night sky. Its wooden platforms rested on soft purple clouds, and its round windows always glowed with creamy moonlight. Inside, generations of moon rabbits shaped rice cakes, repaired broken constellations, carved miniature mallets, and filled lanterns with gentle lunar energy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every evening, the workshop receives requests from distant corners of the sky. Some stars need polishing before they can shine again. Sleeping villages need fresh moonlight delivered to their rooftops. Wandering clouds require new silver bells so they can find their way home. These deliveries are normally carried by experienced couriers, but on the night when Mochiwing Moonflight begins, a sudden cloud current scatters the workshop\u2019s route maps across the sky.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A young rabbit apprentice volunteers to complete the unfinished delivery route. Wearing a small workshop apron and a pair of handcrafted moon wings, the rabbit takes flight through the maze of suspended shelves, wooden support beams, hanging tools, and narrow cloud passages. The journey is not simply a test of speed. It is a test of patience, balance, timing, and courage.<\/p>\n\n\n\n<div id=\"mochiwing-moonflight\" aria-label=\"Mochiwing Moonflight, a Moon Rabbit Workshop flying game\">\n  <div class=\"mmf-stage\">\n    <canvas class=\"mmf-canvas\" aria-label=\"Guide the moon rabbit through workshop gates and collect moon charms\"><\/canvas>\n\n    <div class=\"mmf-hud\">\n      <div class=\"mmf-left-controls\">\n        <button class=\"mmf-icon-button mmf-pause-button\" type=\"button\" aria-label=\"Pause\">\n          <span class=\"mmf-pause-icon\" aria-hidden=\"true\"><\/span>\n        <\/button>\n\n        <button class=\"mmf-icon-button mmf-sound-button\" type=\"button\" aria-label=\"Sound on\">\n          <span class=\"mmf-sound-icon\" aria-hidden=\"true\">\n            <i class=\"mmf-sound-box\"><\/i>\n            <i class=\"mmf-sound-cone\"><\/i>\n            <i class=\"mmf-wave one\"><\/i>\n            <i class=\"mmf-wave two\"><\/i>\n            <i class=\"mmf-wave three\"><\/i>\n            <i class=\"mmf-sound-slash\"><\/i>\n          <\/span>\n        <\/button>\n      <\/div>\n\n      <div class=\"mmf-score-panel\" aria-live=\"polite\">\n        <span class=\"mmf-score-label\">Moon Charms<\/span>\n        <span class=\"mmf-score-value\">0<\/span>\n        <span class=\"mmf-best\">Best 0<\/span>\n      <\/div>\n\n      <div class=\"mmf-shield-pill\">Mochi Moon Shield<\/div>\n    <\/div>\n\n    <div class=\"mmf-modal mmf-show\">\n      <div class=\"mmf-modal-card\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"mmf-modal-title\">\n        <div class=\"mmf-modal-badge\" aria-hidden=\"true\">\n          <span class=\"mmf-badge-moon\"><\/span>\n          <span class=\"mmf-badge-rabbit\"><\/span>\n        <\/div>\n        <p class=\"mmf-modal-title\" id=\"mmf-modal-title\">Mochiwing Moonflight<\/p>\n        <p class=\"mmf-modal-text\">Tap, click, or press Space to guide the tiny moon rabbit through the workshop sky.<\/p>\n        <div class=\"mmf-action-row\">\n          <button class=\"mmf-action mmf-primary\" type=\"button\">Begin Mooncraft Flight<\/button>\n          <button class=\"mmf-action mmf-secondary\" type=\"button\" hidden>Restart<\/button>\n        <\/div>\n        <p class=\"mmf-note\">Collect moon charms. A Mochi Moon Shield absorbs one collision.<\/p>\n      <\/div>\n    <\/div>\n\n    <button class=\"mmf-icon-button mmf-fullscreen-button\" type=\"button\" aria-label=\"Fullscreen\">\n      <span class=\"mmf-fullscreen-icon\" aria-hidden=\"true\"><\/span>\n    <\/button>\n  <\/div>\n<\/div>\n\n<style>\n  html.mmf-page-lock,\n  body.mmf-page-lock {\n    overflow: hidden !important;\n    overscroll-behavior: none;\n  }\n\n  #mochiwing-moonflight,\n  #mochiwing-moonflight * {\n    box-sizing: border-box;\n    user-select: none;\n    -webkit-user-select: none;\n    -webkit-tap-highlight-color: transparent;\n  }\n\n  #mochiwing-moonflight {\n    --mmf-night: #23142f;\n    --mmf-plum: #39244d;\n    --mmf-violet: #57406e;\n    --mmf-lavender: #8b78b8;\n    --mmf-cloud: #cfd1ff;\n    --mmf-cream: #fff1c9;\n    --mmf-ivory: #fff8e7;\n    --mmf-gold: #f4c542;\n    --mmf-wood: #7b5236;\n    --mmf-wood-dark: #4e3024;\n    --mmf-rose: #e58e96;\n    --mmf-mochi: #d9a95b;\n    --mmf-moss: #7e8c5b;\n    --mmf-danger: #d96f6f;\n    --mmf-ink: #31203d;\n    --mmf-muted: #6c5b78;\n    --mmf-panel: rgba(255, 248, 231, .96);\n    --mmf-panel-border: rgba(244, 197, 66, .44);\n    --mmf-icon-bg: linear-gradient(160deg, #6c4c88, #4f3268 58%, #2d193b);\n    --mmf-icon-text: #fff1c9;\n    --mmf-shadow: 0 18px 42px rgba(28, 15, 40, .28);\n\n    position: relative;\n    display: block;\n    width: min(100%, 430px, calc((100dvh - 12px) * 9 \/ 16));\n    aspect-ratio: 9 \/ 16;\n    margin: 0 auto;\n    isolation: isolate;\n    color: var(--mmf-ink);\n    font-family: Arial, Helvetica, sans-serif;\n    touch-action: manipulation;\n  }\n\n  #mochiwing-moonflight button {\n    margin: 0;\n    border: 0;\n    appearance: none;\n    -webkit-appearance: none;\n    font: inherit;\n  }\n\n  #mochiwing-moonflight button:focus-visible {\n    outline: 3px solid rgba(244, 197, 66, .96);\n    outline-offset: 3px;\n  }\n\n  #mochiwing-moonflight:fullscreen,\n  #mochiwing-moonflight:-webkit-full-screen,\n  #mochiwing-moonflight.mmf-fullscreen-fallback {\n    position: fixed;\n    inset: 0;\n    z-index: 2147483647;\n    display: grid;\n    width: 100vw;\n    width: 100dvw;\n    height: 100vh;\n    height: 100dvh;\n    max-width: none;\n    max-height: none;\n    margin: 0;\n    overflow: hidden;\n    place-items: center;\n    background:\n      radial-gradient(circle at 78% 10%, rgba(255, 241, 201, .16), transparent 23%),\n      radial-gradient(circle at 18% 20%, rgba(207, 209, 255, .14), transparent 27%),\n      linear-gradient(155deg, #1c1028 0%, #39244d 54%, #24132f 100%);\n  }\n\n  #mochiwing-moonflight::backdrop {\n    background: linear-gradient(155deg, #1c1028 0%, #39244d 54%, #24132f 100%);\n  }\n\n  #mochiwing-moonflight .mmf-stage {\n    position: relative;\n    width: 100%;\n    height: 100%;\n    aspect-ratio: 9 \/ 16;\n    overflow: hidden;\n    border: 1px solid rgba(244, 197, 66, .36);\n    border-radius: 18px;\n    background: linear-gradient(180deg, #2a173a 0%, #57406e 54%, #25152f 100%);\n    box-shadow: var(--mmf-shadow), inset 0 0 0 1px rgba(255, 241, 201, .08);\n  }\n\n  #mochiwing-moonflight:fullscreen .mmf-stage,\n  #mochiwing-moonflight:-webkit-full-screen .mmf-stage,\n  #mochiwing-moonflight.mmf-fullscreen-fallback .mmf-stage {\n    width: min(100dvw, calc(100dvh * 9 \/ 16));\n    height: min(100dvh, calc(100dvw * 16 \/ 9));\n    max-width: 100dvw;\n    max-height: 100dvh;\n    margin: auto;\n    border: 0;\n    border-radius: 0;\n    box-shadow: none;\n  }\n\n  #mochiwing-moonflight canvas {\n    position: absolute;\n    inset: 0;\n    display: block;\n    width: 100%;\n    height: 100%;\n    background: transparent;\n    transition: filter .18s ease;\n  }\n\n  #mochiwing-moonflight .mmf-stage.mmf-modal-open canvas {\n    filter: blur(1px) brightness(.62) saturate(.86);\n  }\n\n  #mochiwing-moonflight .mmf-hud {\n    position: absolute;\n    inset: 0;\n    z-index: 40;\n    pointer-events: none;\n  }\n\n  #mochiwing-moonflight .mmf-left-controls {\n    position: absolute;\n    top: max(10px, calc(env(safe-area-inset-top, 0px) + 10px));\n    left: max(10px, calc(env(safe-area-inset-left, 0px) + 10px));\n    z-index: 520;\n    display: flex;\n    gap: 8px;\n    pointer-events: auto;\n  }\n\n  #mochiwing-moonflight .mmf-icon-button {\n    display: grid;\n    width: clamp(38px, 10vw, 44px);\n    height: clamp(38px, 10vw, 44px);\n    padding: 0;\n    place-items: center;\n    border: 1px solid rgba(255, 241, 201, .72);\n    border-radius: 14px;\n    color: var(--mmf-icon-text);\n    cursor: pointer;\n    pointer-events: auto;\n    background: var(--mmf-icon-bg);\n    box-shadow: 0 8px 18px rgba(25, 12, 36, .28), inset 0 1px 0 rgba(255, 241, 201, .18);\n    transition: transform .14s ease, filter .14s ease, border-color .14s ease;\n  }\n\n  #mochiwing-moonflight .mmf-icon-button:hover,\n  #mochiwing-moonflight .mmf-icon-button:focus-visible {\n    border-color: var(--mmf-gold);\n    filter: brightness(1.10);\n    transform: translateY(-1px);\n  }\n\n  #mochiwing-moonflight .mmf-icon-button:active,\n  #mochiwing-moonflight .mmf-action:active {\n    transform: translateY(1px) scale(.96);\n  }\n\n  #mochiwing-moonflight .mmf-fullscreen-button {\n    position: absolute;\n    top: max(10px, calc(env(safe-area-inset-top, 0px) + 10px));\n    right: max(10px, calc(env(safe-area-inset-right, 0px) + 10px));\n    z-index: 540;\n    visibility: visible;\n    opacity: 1;\n    pointer-events: auto;\n  }\n\n  #mochiwing-moonflight .mmf-score-panel {\n    position: absolute;\n    top: max(10px, calc(env(safe-area-inset-top, 0px) + 10px));\n    left: 50%;\n    min-width: clamp(128px, 37vw, 156px);\n    padding: 8px 13px 9px;\n    border: 1px solid var(--mmf-panel-border);\n    border-radius: 16px;\n    text-align: center;\n    transform: translateX(-50%);\n    background: var(--mmf-panel);\n    box-shadow: 0 10px 22px rgba(25, 12, 36, .18), inset 0 1px 0 rgba(255, 255, 255, .50);\n  }\n\n  #mochiwing-moonflight .mmf-score-panel::before {\n    content: \"\";\n    position: absolute;\n    left: 50%;\n    top: 4px;\n    width: 44px;\n    height: 3px;\n    border-radius: 999px;\n    transform: translateX(-50%);\n    background: linear-gradient(90deg, var(--mmf-lavender), var(--mmf-gold));\n  }\n\n  #mochiwing-moonflight .mmf-score-label {\n    display: block;\n    color: var(--mmf-muted);\n    font-size: 9px;\n    font-weight: 900;\n    letter-spacing: .13em;\n    line-height: 1;\n    text-transform: uppercase;\n  }\n\n  #mochiwing-moonflight .mmf-score-value {\n    display: block;\n    margin-top: 4px;\n    color: var(--mmf-ink);\n    font-family: Georgia, \"Times New Roman\", serif;\n    font-size: clamp(24px, 7vw, 29px);\n    font-weight: 900;\n    line-height: .95;\n  }\n\n  #mochiwing-moonflight .mmf-best {\n    display: inline-block;\n    margin-top: 6px;\n    padding: 3px 9px;\n    border-radius: 999px;\n    color: var(--mmf-cream);\n    background: var(--mmf-plum);\n    font-size: 9.5px;\n    font-weight: 850;\n    line-height: 1;\n  }\n\n  #mochiwing-moonflight .mmf-shield-pill {\n    position: absolute;\n    top: max(100px, calc(env(safe-area-inset-top, 0px) + 100px));\n    left: 50%;\n    padding: 7px 13px 7px 31px;\n    border: 1px solid rgba(255, 241, 201, .72);\n    border-radius: 999px;\n    color: var(--mmf-cream);\n    background: var(--mmf-icon-bg);\n    box-shadow: 0 8px 18px rgba(25, 12, 36, .24), 0 0 18px rgba(244, 197, 66, .18);\n    font-size: 9px;\n    font-weight: 900;\n    letter-spacing: .07em;\n    text-transform: uppercase;\n    opacity: 0;\n    transform: translateX(-50%) translateY(-5px) scale(.96);\n    transition: opacity .18s ease, transform .18s ease;\n  }\n\n  #mochiwing-moonflight .mmf-shield-pill::before {\n    content: \"\";\n    position: absolute;\n    left: 9px;\n    top: 50%;\n    width: 16px;\n    height: 13px;\n    margin-top: -6.5px;\n    border: 2px solid var(--mmf-cream);\n    border-radius: 50% 50% 45% 45%;\n    background: var(--mmf-mochi);\n    box-shadow: inset 4px 3px 0 rgba(255, 248, 231, .35), 0 0 0 2px rgba(35, 20, 47, .16);\n  }\n\n  #mochiwing-moonflight .mmf-shield-pill.mmf-show {\n    opacity: 1;\n    transform: translateX(-50%) translateY(0) scale(1);\n  }\n\n  #mochiwing-moonflight .mmf-modal {\n    position: absolute;\n    inset: 0;\n    z-index: 220;\n    display: none;\n    align-items: center;\n    justify-content: center;\n    padding: 22px;\n    overflow: hidden;\n    border-radius: inherit;\n    background: rgba(24, 13, 34, .54);\n    backdrop-filter: blur(7px) saturate(.9);\n  }\n\n  #mochiwing-moonflight .mmf-modal.mmf-show {\n    display: flex;\n  }\n\n  #mochiwing-moonflight .mmf-modal-card {\n    width: min(100%, 300px);\n    padding: 20px 18px 18px;\n    border: 1px solid var(--mmf-panel-border);\n    border-radius: 20px;\n    text-align: center;\n    background:\n      radial-gradient(circle at 84% 6%, rgba(244, 197, 66, .20), transparent 31%),\n      radial-gradient(circle at 16% 12%, rgba(207, 209, 255, .24), transparent 34%),\n      linear-gradient(180deg, rgba(255, 248, 231, .98), rgba(232, 221, 245, .96));\n    box-shadow: 0 22px 52px rgba(24, 13, 34, .34), inset 0 1px 0 rgba(255, 255, 255, .45);\n  }\n\n  #mochiwing-moonflight .mmf-modal-badge {\n    position: relative;\n    width: 80px;\n    height: 80px;\n    margin: 0 auto 11px;\n    border: 2px solid rgba(123, 82, 54, .72);\n    border-radius: 20px;\n    background: linear-gradient(180deg, var(--mmf-cream), #e2d4f0);\n    box-shadow: 0 10px 22px rgba(36, 20, 47, .18);\n    overflow: hidden;\n  }\n\n  #mochiwing-moonflight .mmf-badge-moon {\n    position: absolute;\n    width: 48px;\n    height: 48px;\n    right: 5px;\n    top: 6px;\n    border-radius: 50%;\n    background: var(--mmf-gold);\n    box-shadow: inset -12px -4px 0 rgba(255, 248, 231, .78), 0 0 18px rgba(244, 197, 66, .34);\n  }\n\n  #mochiwing-moonflight .mmf-badge-rabbit {\n    position: absolute;\n    left: 21px;\n    bottom: 10px;\n    width: 38px;\n    height: 29px;\n    border-radius: 50% 50% 46% 46%;\n    background: var(--mmf-rose);\n    box-shadow: inset -5px -5px 0 rgba(49, 32, 61, .08);\n  }\n\n  #mochiwing-moonflight .mmf-badge-rabbit::before {\n    content: \"\";\n    position: absolute;\n    left: 7px;\n    top: -21px;\n    width: 8px;\n    height: 27px;\n    border-radius: 999px;\n    background: var(--mmf-rose);\n    box-shadow: 17px 0 0 var(--mmf-rose);\n  }\n\n  #mochiwing-moonflight .mmf-badge-rabbit::after {\n    content: \"\";\n    position: absolute;\n    left: 11px;\n    top: 10px;\n    width: 4px;\n    height: 4px;\n    border-radius: 50%;\n    background: var(--mmf-ink);\n    box-shadow: 12px 0 0 var(--mmf-ink), 6px 8px 0 -1px rgba(255, 248, 231, .8);\n  }\n\n  #mochiwing-moonflight .mmf-modal-title {\n    margin: 0 0 8px;\n    color: var(--mmf-ink);\n    font-family: Georgia, \"Times New Roman\", serif;\n    font-size: 25px;\n    font-weight: 900;\n    letter-spacing: -.025em;\n    line-height: 1.06;\n  }\n\n  #mochiwing-moonflight .mmf-modal-text {\n    margin: 0;\n    color: var(--mmf-muted);\n    font-size: 13px;\n    line-height: 1.46;\n  }\n\n  #mochiwing-moonflight .mmf-note {\n    margin: 10px 0 0;\n    color: var(--mmf-muted);\n    font-size: 11px;\n    line-height: 1.45;\n  }\n\n  #mochiwing-moonflight .mmf-action-row {\n    display: flex;\n    flex-direction: column;\n    gap: 9px;\n    margin-top: 14px;\n  }\n\n  #mochiwing-moonflight .mmf-action {\n    min-height: 44px;\n    padding: 0 14px;\n    border: 1px solid rgba(57, 36, 77, .18);\n    border-radius: 14px;\n    cursor: pointer;\n    font-size: 13px;\n    font-weight: 900;\n    letter-spacing: .01em;\n    transition: transform .14s ease, filter .14s ease, box-shadow .14s ease;\n  }\n\n  #mochiwing-moonflight .mmf-action:hover,\n  #mochiwing-moonflight .mmf-action:focus-visible {\n    transform: translateY(-1px);\n    filter: brightness(1.05);\n    box-shadow: 0 10px 18px rgba(36, 20, 47, .14);\n  }\n\n  #mochiwing-moonflight .mmf-primary {\n    color: #3b2748;\n    background: linear-gradient(180deg, #fff8df, #f4c542);\n  }\n\n  #mochiwing-moonflight .mmf-secondary {\n    color: var(--mmf-cream);\n    background: linear-gradient(160deg, #8b78b8, #5a3f78 64%, #39244d);\n  }\n\n  #mochiwing-moonflight .mmf-pause-icon,\n  #mochiwing-moonflight .mmf-sound-icon,\n  #mochiwing-moonflight .mmf-fullscreen-icon {\n    position: relative;\n    display: block;\n  }\n\n  #mochiwing-moonflight .mmf-pause-icon {\n    width: 18px;\n    height: 18px;\n  }\n\n  #mochiwing-moonflight .mmf-pause-icon::before,\n  #mochiwing-moonflight .mmf-pause-icon::after {\n    content: \"\";\n    position: absolute;\n    top: 1px;\n    width: 5px;\n    height: 16px;\n    border-radius: 3px;\n    background: currentColor;\n  }\n\n  #mochiwing-moonflight .mmf-pause-icon::before { left: 3px; }\n  #mochiwing-moonflight .mmf-pause-icon::after { right: 3px; }\n\n  #mochiwing-moonflight .mmf-sound-icon {\n    width: 25px;\n    height: 20px;\n    transform: translateX(-1px);\n  }\n\n  #mochiwing-moonflight .mmf-sound-box,\n  #mochiwing-moonflight .mmf-sound-cone,\n  #mochiwing-moonflight .mmf-wave,\n  #mochiwing-moonflight .mmf-sound-slash {\n    position: absolute;\n    display: block;\n  }\n\n  #mochiwing-moonflight .mmf-sound-box {\n    left: 0;\n    top: 6px;\n    width: 7px;\n    height: 8px;\n    border-radius: 3px 0 0 3px;\n    background: currentColor;\n  }\n\n  #mochiwing-moonflight .mmf-sound-cone {\n    left: 6px;\n    top: 3px;\n    width: 9px;\n    height: 14px;\n    background: currentColor;\n    clip-path: polygon(0 32%, 100% 0, 100% 100%, 0 68%);\n  }\n\n  #mochiwing-moonflight .mmf-wave {\n    border-style: solid;\n    border-color: currentColor;\n    border-left-color: transparent;\n    border-top-color: transparent;\n    border-bottom-color: transparent;\n    border-radius: 0 999px 999px 0;\n    background: transparent;\n    transition: opacity .14s ease;\n  }\n\n  #mochiwing-moonflight .mmf-wave.one {\n    left: 13px;\n    top: 7px;\n    width: 4px;\n    height: 6px;\n    border-width: 2px;\n  }\n\n  #mochiwing-moonflight .mmf-wave.two {\n    left: 15px;\n    top: 4px;\n    width: 7px;\n    height: 12px;\n    border-width: 2px;\n  }\n\n  #mochiwing-moonflight .mmf-wave.three {\n    left: 17px;\n    top: 1px;\n    width: 8px;\n    height: 18px;\n    border-width: 2px;\n  }\n\n  #mochiwing-moonflight .mmf-sound-slash {\n    left: -2px;\n    top: 9px;\n    width: 27px;\n    height: 3px;\n    border-radius: 999px;\n    background: var(--mmf-danger);\n    transform: rotate(45deg) scaleX(0);\n    transform-origin: center;\n    box-shadow: 0 0 7px rgba(217, 111, 111, .35);\n    transition: transform .14s ease;\n  }\n\n  #mochiwing-moonflight.mmf-muted .mmf-wave { opacity: 0; }\n  #mochiwing-moonflight.mmf-muted .mmf-sound-slash { transform: rotate(45deg) scaleX(1); }\n\n  #mochiwing-moonflight .mmf-fullscreen-icon {\n    width: 22px;\n    height: 22px;\n  }\n\n  #mochiwing-moonflight .mmf-fullscreen-icon::before {\n    content: \"\";\n    position: absolute;\n    inset: 1px;\n    background:\n      linear-gradient(currentColor,currentColor) left top \/ 9px 3px no-repeat,\n      linear-gradient(currentColor,currentColor) left top \/ 3px 9px no-repeat,\n      linear-gradient(currentColor,currentColor) right top \/ 9px 3px no-repeat,\n      linear-gradient(currentColor,currentColor) right top \/ 3px 9px no-repeat,\n      linear-gradient(currentColor,currentColor) left bottom \/ 9px 3px no-repeat,\n      linear-gradient(currentColor,currentColor) left bottom \/ 3px 9px no-repeat,\n      linear-gradient(currentColor,currentColor) right bottom \/ 9px 3px no-repeat,\n      linear-gradient(currentColor,currentColor) right bottom \/ 3px 9px no-repeat;\n  }\n\n  @media (max-width: 520px) {\n    #mochiwing-moonflight { width: 100%; }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    #mochiwing-moonflight *,\n    #mochiwing-moonflight *::before,\n    #mochiwing-moonflight *::after {\n      animation-duration: .01ms !important;\n      transition-duration: .01ms !important;\n    }\n  }\n<\/style>\n\n<script>(function () {\n  \"use strict\";\n\n  \/\/ Preserve JavaScript short-circuit semantics without an ampersand token.\n  function mmfAnd(value, rightSide) {\n    return value ? rightSide() : value;\n  }\n\n  const root = document.getElementById(\"mochiwing-moonflight\");\n  if (!root || root.dataset.mmfReady === \"1\") return;\n  root.dataset.mmfReady = \"1\";\n  root.setAttribute(\"tabindex\", \"0\");\n\n  const stage = root.querySelector(\".mmf-stage\");\n  const canvas = root.querySelector(\".mmf-canvas\");\n  const ctx = canvas.getContext(\"2d\");\n  const modal = root.querySelector(\".mmf-modal\");\n  const modalTitle = root.querySelector(\".mmf-modal-title\");\n  const modalText = root.querySelector(\".mmf-modal-text\");\n  const note = root.querySelector(\".mmf-note\");\n  const primaryButton = root.querySelector(\".mmf-primary\");\n  const secondaryButton = root.querySelector(\".mmf-secondary\");\n  const pauseButton = root.querySelector(\".mmf-pause-button\");\n  const soundButton = root.querySelector(\".mmf-sound-button\");\n  const fullscreenButton = root.querySelector(\".mmf-fullscreen-button\");\n  const scoreElement = root.querySelector(\".mmf-score-value\");\n  const bestElement = root.querySelector(\".mmf-best\");\n  const shieldElement = root.querySelector(\".mmf-shield-pill\");\n\n  const W = 360;\n  const H = 640;\n  const ROUTE_BOTTOM = 640;\n  const BEST_KEY = \"repedia_mochiwing_moonflight_best_v1\";\n  const MUTE_KEY = \"repedia_mochiwing_moonflight_muted_v1\";\n  const DPR_LIMIT = 2;\n\n  let dpr = 1;\n  let lastTime = performance.now();\n  let audioContext = null;\n  let resizeFrame = 0;\n  let fallbackFullscreen = false;\n  let gameInView = true;\n  let player = null;\n  let gates = [];\n  let particles = [];\n  let nextGateDistance = 226;\n\n  const state = {\n    screen: \"start\",\n    score: 0,\n    best: Number(readStorage(BEST_KEY, 0)) || 0,\n    muted: readStorage(MUTE_KEY, \"0\") === \"1\",\n    gameStarted: false,\n    gameOver: false,\n    paused: false,\n    time: 0,\n    shield: false,\n    shieldFlash: 0,\n    shake: 0,\n    pulse: 0,\n    idleTime: 0,\n    justStarted: 0,\n    milestone: 0\n  };\n\n  const rand = (a, b) => a + Math.random() * (b - a);\n  const clamp = (value, min, max) => Math.max(min, Math.min(max, value));\n\n  function readStorage(key, fallback) {\n    try {\n      const value = localStorage.getItem(key);\n      return value == null ? fallback : value;\n    } catch (error) {\n      return fallback;\n    }\n  }\n\n  function writeStorage(key, value) {\n    try {\n      localStorage.setItem(key, value);\n    } catch (error) {}\n  }\n\n  function roundRect(x, y, width, height, radius) {\n    const r = Math.min(radius, width \/ 2, height \/ 2);\n    ctx.beginPath();\n    ctx.moveTo(x + r, y);\n    ctx.arcTo(x + width, y, x + width, y + height, r);\n    ctx.arcTo(x + width, y + height, x, y + height, r);\n    ctx.arcTo(x, y + height, x, y, r);\n    ctx.arcTo(x, y, x + width, y, r);\n    ctx.closePath();\n  }\n\n  function palette() {\n    return {\n      night: \"#23142f\",\n      plum: \"#39244d\",\n      violet: \"#57406e\",\n      lavender: \"#8b78b8\",\n      cloud: \"#cfd1ff\",\n      cream: \"#fff1c9\",\n      ivory: \"#fff8e7\",\n      gold: \"#f4c542\",\n      wood: \"#7b5236\",\n      woodDark: \"#4e3024\",\n      rose: \"#e58e96\",\n      mochi: \"#d9a95b\",\n      moss: \"#7e8c5b\",\n      ink: \"#31203d\",\n      glow: \"rgba(244,197,66,.32)\"\n    };\n  }\n\n  function queueResize() {\n    cancelAnimationFrame(resizeFrame);\n    resizeFrame = requestAnimationFrame(function () {\n      resizeCanvas();\n      draw();\n    });\n  }\n\n  function resizeCanvas() {\n    dpr = Math.min(window.devicePixelRatio || 1, DPR_LIMIT);\n    canvas.width = Math.round(W * dpr);\n    canvas.height = Math.round(H * dpr);\n    canvas.style.width = \"100%\";\n    canvas.style.height = \"100%\";\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    ctx.imageSmoothingEnabled = true;\n  }\n\n  function getAudioContext() {\n    if (state.muted) return null;\n    const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n    if (!AudioContextClass) return null;\n    if (!audioContext) {\n      try { audioContext = new AudioContextClass(); } catch (error) { return null; }\n    }\n    if (audioContext.state === \"suspended\") {\n      try {\n        const resumed = audioContext.resume();\n        if (resumed) {\n          if (typeof resumed.catch === \"function\") resumed.catch(function () {});\n        }\n      } catch (error) {}\n    }\n    return audioContext;\n  }\n\n  function playTone(ac, frequency, start, duration, volume, type) {\n    const oscillator = ac.createOscillator();\n    const gain = ac.createGain();\n    oscillator.type = type || \"sine\";\n    oscillator.frequency.setValueAtTime(frequency, start);\n    gain.gain.setValueAtTime(.0001, start);\n    gain.gain.exponentialRampToValueAtTime(volume, start + .012);\n    gain.gain.exponentialRampToValueAtTime(.0001, start + duration);\n    oscillator.connect(gain);\n    gain.connect(ac.destination);\n    oscillator.start(start);\n    oscillator.stop(start + duration + .03);\n  }\n\n  function playSound(type) {\n    if (state.muted) return;\n    const ac = getAudioContext();\n    if (!ac) return;\n    const now = ac.currentTime;\n\n    if (type === \"flap\") {\n      playTone(ac, 410, now, .065, .020, \"triangle\");\n      playTone(ac, 560, now + .025, .055, .013, \"sine\");\n    } else if (type === \"score\") {\n      playTone(ac, 640, now, .09, .024, \"sine\");\n      playTone(ac, 840, now + .045, .105, .018, \"triangle\");\n    } else if (type === \"shield\") {\n      playTone(ac, 350, now, .14, .026, \"sine\");\n      playTone(ac, 520, now + .05, .16, .022, \"triangle\");\n      playTone(ac, 720, now + .1, .18, .017, \"sine\");\n    } else if (type === \"break\") {\n      playTone(ac, 235, now, .13, .028, \"triangle\");\n      playTone(ac, 155, now + .05, .18, .022, \"sine\");\n    } else if (type === \"hit\") {\n      playTone(ac, 180, now, .17, .032, \"triangle\");\n      playTone(ac, 108, now + .06, .23, .024, \"sine\");\n    } else if (type === \"start\") {\n      playTone(ac, 392, now, .10, .020, \"sine\");\n      playTone(ac, 523, now + .05, .13, .019, \"triangle\");\n      playTone(ac, 698, now + .1, .17, .016, \"sine\");\n    } else if (type === \"pause\") {\n      playTone(ac, 350, now, .09, .018, \"triangle\");\n      playTone(ac, 250, now + .045, .11, .014, \"sine\");\n    } else if (type === \"resume\") {\n      playTone(ac, 320, now, .08, .016, \"triangle\");\n      playTone(ac, 480, now + .04, .11, .016, \"sine\");\n    } else if (type === \"milestone\") {\n      playTone(ac, 523, now, .12, .022, \"triangle\");\n      playTone(ac, 659, now + .055, .14, .020, \"sine\");\n      playTone(ac, 784, now + .11, .18, .018, \"triangle\");\n    }\n  }\n\n  function syncInterface() {\n    scoreElement.textContent = String(state.score);\n    bestElement.textContent = \"Best \" + state.best;\n    shieldElement.classList.toggle(\"mmf-show\", state.shield);\n    root.classList.toggle(\"mmf-muted\", state.muted);\n    stage.classList.toggle(\"mmf-modal-open\", modal.classList.contains(\"mmf-show\"));\n    soundButton.setAttribute(\"aria-label\", state.muted ? \"Sound muted\" : \"Sound on\");\n  }\n\n  function resetGame() {\n    state.score = 0;\n    state.gameStarted = false;\n    state.gameOver = false;\n    state.paused = false;\n    state.time = 0;\n    state.shield = false;\n    state.shieldFlash = 0;\n    state.shake = 0;\n    state.pulse = 0;\n    state.idleTime = 0;\n    state.justStarted = 0;\n    state.milestone = 0;\n    gates = [];\n    particles = [];\n    nextGateDistance = 216;\n\n    player = {\n      x: 92,\n      y: 314,\n      radius: 17,\n      vy: 0,\n      rotation: 0,\n      wingBeat: 0,\n      flapStretch: 0,\n      sparkle: 0\n    };\n\n    spawnGate(W + 112);\n    syncInterface();\n  }\n\n  function showModal(type) {\n    modal.classList.add(\"mmf-show\");\n\n    if (type === \"start\") {\n      modalTitle.textContent = \"Mochiwing Moonflight\";\n      modalText.textContent = \"Tap, click, or press Space to guide the tiny moon rabbit through the workshop sky.\";\n      note.textContent = \"Collect moon charms. A Mochi Moon Shield absorbs one collision.\";\n      primaryButton.textContent = \"Begin Mooncraft Flight\";\n      secondaryButton.hidden = true;\n    } else if (type === \"pause\") {\n      modalTitle.textContent = \"Moonlight Pause\";\n      modalText.textContent = \"The workshop clouds wait while the little rabbit rests beside the glowing moon.\";\n      note.textContent = \"Resume when you are ready to continue through the next workshop gate.\";\n      primaryButton.textContent = \"Return to the Workshop\";\n      secondaryButton.textContent = \"Restart Flight\";\n      secondaryButton.hidden = false;\n    } else {\n      modalTitle.textContent = \"The Mooncraft Flight Ended\";\n      modalText.textContent = \"The little rabbit touched a workshop gate before reaching the next cloud passage.\";\n      note.textContent = \"Your best score is saved automatically. Follow the open moon path and try again.\";\n      primaryButton.textContent = \"Fly Again\";\n      secondaryButton.textContent = \"Fresh Flight\";\n      secondaryButton.hidden = false;\n    }\n\n    syncInterface();\n  }\n\n  function hideModal() {\n    modal.classList.remove(\"mmf-show\");\n    syncInterface();\n  }\n\n  function startGame() {\n    resetGame();\n    try { root.focus({ preventScroll: true }); } catch (ignore) { root.focus(); }\n    state.gameStarted = true;\n    state.screen = \"play\";\n    state.justStarted = .32;\n    hideModal();\n    playSound(\"start\");\n  }\n\n  function pauseGame() {\n    if (!state.gameStarted || state.gameOver) return;\n    state.paused = true;\n    state.screen = \"pause\";\n    showModal(\"pause\");\n    playSound(\"pause\");\n  }\n\n  function resumeGame() {\n    if (!state.paused || state.gameOver) return;\n    state.paused = false;\n    state.screen = \"play\";\n    hideModal();\n    playSound(\"resume\");\n  }\n\n  function gameOver() {\n    state.gameOver = true;\n    state.gameStarted = false;\n    state.screen = \"gameover\";\n    if (state.score > state.best) {\n      state.best = state.score;\n      writeStorage(BEST_KEY, String(state.best));\n    }\n    syncInterface();\n    showModal(\"gameover\");\n    playSound(\"hit\");\n  }\n\n  function flap(silent) {\n    if (!player) return;\n    player.vy = -248;\n    player.flapStretch = 1;\n    player.sparkle = .18;\n    if (!silent) playSound(\"flap\");\n  }\n\n  function addScore(amount, soundType) {\n    state.score += amount;\n    state.pulse = .22;\n    if (state.score > state.best) {\n      state.best = state.score;\n      writeStorage(BEST_KEY, String(state.best));\n    }\n    const currentMilestone = Math.floor(state.score \/ 10);\n    if (currentMilestone > state.milestone) {\n      state.milestone = currentMilestone;\n      playSound(\"milestone\");\n      burst(player.x + 8, player.y, 20, \"spark\");\n    } else if (soundType) {\n      playSound(soundType);\n    }\n    syncInterface();\n  }\n\n  function spawnGate(x) {\n    const gapHeight = clamp(194 - state.score * .50, 146, 194);\n    const gapY = rand(116 + gapHeight \/ 2, 572 - gapHeight \/ 2);\n    const width = rand(62, 70);\n    const charmY = clamp(gapY + rand(-gapHeight * .26, gapHeight * .26), 120, 550);\n\n    gates.push({\n      x: x,\n      width: width,\n      gapY: gapY,\n      gapHeight: gapHeight,\n      style: Math.floor(rand(0, 4)),\n      passed: false,\n      hitCooldown: 0,\n      charm: {\n        y: charmY,\n        offsetX: width * .5,\n        radius: 10,\n        collected: false,\n        spin: rand(0, Math.PI * 2)\n      },\n      shieldItem: Math.random() < .16 ? {\n        y: clamp(charmY + rand(-48, 48), 132, 532),\n        offsetX: width * .5,\n        radius: 12,\n        collected: false,\n        pulse: rand(0, Math.PI * 2)\n      } : null\n    });\n  }\n\n  function burst(x, y, count, type) {\n    const c = palette();\n    const colors = [c.cream, c.gold, c.rose, c.cloud, c.lavender, c.mochi];\n\n    for (let i = 0; i < count; i++) {\n      const angle = rand(0, Math.PI * 2);\n      const speed = type === \"shard\" ? rand(70, 190) : rand(35, 116);\n      const life = type === \"shard\" ? rand(.36, .72) : rand(.3, .68);\n      particles.push({\n        x: x,\n        y: y,\n        vx: Math.cos(angle) * speed,\n        vy: Math.sin(angle) * speed,\n        life: life,\n        maxLife: life,\n        radius: type === \"shard\" ? rand(2, 4.8) : rand(1.3, 3.2),\n        color: colors[Math.floor(rand(0, colors.length))],\n        gravity: type === \"shard\" ? 84 : 34,\n        crumb: Math.random() < .55,\n        rotation: rand(0, Math.PI * 2),\n        spin: rand(-7, 7),\n        fade: rand(.84, 1.04)\n      });\n    }\n  }\n\n  function circleRectangleCollision(cx, cy, radius, rx, ry, width, height) {\n    const nearestX = clamp(cx, rx, rx + width);\n    const nearestY = clamp(cy, ry, ry + height);\n    const dx = cx - nearestX;\n    const dy = cy - nearestY;\n    return dx * dx + dy * dy < radius * radius;\n  }\n\n  function breakShield(gate) {\n    state.shield = false;\n    state.shieldFlash = .36;\n    state.shake = .42;\n    player.vy = -132;\n    burst(player.x, player.y, 22, \"shard\");\n    playSound(\"break\");\n    if (gate) {\n      gate.hitCooldown = .5;\n      gate.x -= 18;\n    }\n    syncInterface();\n  }\n\n  function update(deltaTime) {\n    state.idleTime += deltaTime;\n\n    if (state.paused || state.gameOver || !state.gameStarted) {\n      player.wingBeat += deltaTime * 3;\n      player.sparkle = Math.max(0, player.sparkle - deltaTime * .4);\n      updateParticles(deltaTime * .35);\n      return;\n    }\n\n    state.time += deltaTime;\n    player.wingBeat += deltaTime * 8;\n    player.flapStretch = Math.max(0, player.flapStretch - deltaTime * 4.8);\n    player.sparkle = Math.max(0, player.sparkle - deltaTime * .7);\n    state.pulse = Math.max(0, state.pulse - deltaTime * 2.8);\n    state.shieldFlash = Math.max(0, state.shieldFlash - deltaTime * 3.2);\n    state.shake = Math.max(0, state.shake - deltaTime * 2.5);\n    state.justStarted = Math.max(0, state.justStarted - deltaTime);\n\n    const speed = Math.min(214, 121 + state.score * 1.25 + state.time * .30);\n    player.vy += 692 * deltaTime;\n    player.y += player.vy * deltaTime;\n    player.rotation = clamp(player.vy \/ 320, -1.1, 1.1);\n\n    if (player.y < 33) {\n      if (state.shield) {\n        player.y = 33;\n        breakShield(null);\n      } else {\n        gameOver();\n        return;\n      }\n    }\n\n    if (player.y > ROUTE_BOTTOM - player.radius) {\n      if (state.shield) {\n        player.y = ROUTE_BOTTOM - player.radius;\n        breakShield(null);\n      } else {\n        gameOver();\n        return;\n      }\n    }\n\n    for (const gate of gates) {\n      gate.x -= speed * deltaTime;\n      gate.hitCooldown = Math.max(0, gate.hitCooldown - deltaTime);\n\n      if (mmfAnd((!gate.passed), () => (gate.x + gate.width < player.x))) {\n        gate.passed = true;\n        addScore(1, \"score\");\n      }\n\n      collectItems(gate);\n      checkCollision(gate);\n      gate.charm.spin += deltaTime * 3.2;\n      if (gate.shieldItem) gate.shieldItem.pulse += deltaTime * 4.2;\n      if (state.gameOver) return;\n    }\n\n    const lastGate = gates[gates.length - 1];\n    if (mmfAnd((lastGate), () => (lastGate.x < W - nextGateDistance))) {\n      nextGateDistance = rand(214, 260) - Math.min(18, state.score * .42);\n      spawnGate(W + 44);\n    }\n\n    gates = gates.filter(function (gate) {\n      return gate.x + gate.width > -82;\n    });\n\n    updateParticles(deltaTime);\n  }\n\n  function collectItems(gate) {\n    if (!gate.charm.collected) {\n      const x = gate.x + gate.charm.offsetX;\n      const y = gate.charm.y;\n      const dx = player.x - x;\n      const dy = player.y - y;\n\n      if (dx * dx + dy * dy < Math.pow(player.radius + gate.charm.radius + 3, 2)) {\n        gate.charm.collected = true;\n        addScore(2, \"score\");\n        burst(x, y, 16, \"spark\");\n      }\n    }\n\n    if (mmfAnd((gate.shieldItem), () => (!gate.shieldItem.collected))) {\n      const x = gate.x + gate.shieldItem.offsetX;\n      const y = gate.shieldItem.y;\n      const dx = player.x - x;\n      const dy = player.y - y;\n\n      if (dx * dx + dy * dy < Math.pow(player.radius + gate.shieldItem.radius + 4, 2)) {\n        gate.shieldItem.collected = true;\n        state.shield = true;\n        state.shieldFlash = .46;\n        burst(x, y, 19, \"spark\");\n        playSound(\"shield\");\n        syncInterface();\n      }\n    }\n  }\n\n  function checkCollision(gate) {\n    if (gate.hitCooldown > 0) return;\n\n    const topHeight = gate.gapY - gate.gapHeight \/ 2;\n    const bottomY = gate.gapY + gate.gapHeight \/ 2;\n    const collisionX = gate.x + 8;\n    const collisionWidth = gate.width - 16;\n    const radius = player.radius * .82;\n\n    const topCollision = circleRectangleCollision(player.x, player.y, radius, collisionX, -10, collisionWidth, topHeight + 10);\n    const bottomCollision = circleRectangleCollision(player.x, player.y, radius, collisionX, bottomY, collisionWidth, H - bottomY + 10);\n\n    if (topCollision || bottomCollision) {\n      if (state.shield) breakShield(gate);\n      else {\n        burst(player.x, player.y, 26, \"shard\");\n        gameOver();\n      }\n    }\n  }\n\n  function updateParticles(deltaTime) {\n    for (const particle of particles) {\n      particle.life -= deltaTime * particle.fade;\n      particle.x += particle.vx * deltaTime;\n      particle.y += particle.vy * deltaTime;\n      particle.vy += particle.gravity * deltaTime;\n      particle.vx *= .986;\n      particle.rotation += particle.spin * deltaTime;\n    }\n\n    particles = particles.filter(function (particle) {\n      return particle.life > 0;\n    });\n  }\n\n  function draw() {\n    ctx.clearRect(0, 0, W, H);\n\n    let shakeX = 0;\n    let shakeY = 0;\n    if (state.shake > 0) {\n      const amplitude = state.shake * 9;\n      const wave = state.time * 92;\n      shakeX = Math.sin(wave) * amplitude;\n      shakeY = Math.cos(wave * 1.7) * amplitude * .34;\n    }\n\n    ctx.save();\n    ctx.translate(shakeX, shakeY);\n\n    drawMoonSky();\n    drawCloudLayers();\n    drawWorkshopSilhouette();\n    drawStarDust();\n    gates.forEach(drawGate);\n    drawParticles();\n    drawMoonRabbit();\n    drawHangingLanterns();\n\n    ctx.restore();\n  }\n\n  function drawMoonSky() {\n    const c = palette();\n    const bg = ctx.createLinearGradient(0, 0, 0, H);\n    bg.addColorStop(0, \"#20112c\");\n    bg.addColorStop(.48, c.violet);\n    bg.addColorStop(1, \"#2a1837\");\n    ctx.fillStyle = bg;\n    ctx.fillRect(0, 0, W, H);\n\n    const moonX = 285;\n    const moonY = 116;\n    const moonGlow = ctx.createRadialGradient(moonX, moonY, 8, moonX, moonY, 92);\n    moonGlow.addColorStop(0, \"rgba(255,248,231,.96)\");\n    moonGlow.addColorStop(.36, \"rgba(255,241,201,.44)\");\n    moonGlow.addColorStop(1, \"rgba(244,197,66,0)\");\n    ctx.fillStyle = moonGlow;\n    ctx.beginPath();\n    ctx.arc(moonX, moonY, 92, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.cream;\n    ctx.beginPath();\n    ctx.arc(moonX, moonY, 49, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = \"rgba(139,120,184,.18)\";\n    ctx.beginPath();\n    ctx.arc(moonX - 15, moonY - 12, 8, 0, Math.PI * 2);\n    ctx.arc(moonX + 18, moonY + 10, 6, 0, Math.PI * 2);\n    ctx.arc(moonX - 6, moonY + 24, 5, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = \"rgba(207,209,255,.18)\";\n    ctx.fillRect(0, 0, 22, H);\n    ctx.fillRect(W - 22, 0, 22, H);\n\n    ctx.strokeStyle = \"rgba(244,197,66,.18)\";\n    ctx.lineWidth = 1;\n    for (let y = 78; y < H; y += 72) {\n      ctx.beginPath();\n      ctx.moveTo(4, y);\n      ctx.lineTo(18, y);\n      ctx.moveTo(W - 18, y);\n      ctx.lineTo(W - 4, y);\n      ctx.stroke();\n    }\n  }\n\n  function drawCloudLayers() {\n    const c = palette();\n    const offsetBack = (state.idleTime * 8) % 230;\n    const offsetFront = (state.idleTime * 18) % 260;\n\n    ctx.save();\n    ctx.globalAlpha = .42;\n    for (let i = -1; i < 3; i++) {\n      drawCloud(i * 230 - offsetBack + 28, 206 + (i % 2) * 56, 1.18, c.cloud);\n    }\n    ctx.restore();\n\n    ctx.save();\n    ctx.globalAlpha = .52;\n    for (let i = -1; i < 3; i++) {\n      drawCloud(i * 260 - offsetFront + 42, 436 + (i % 2) * 48, .98, \"#b9afe0\");\n    }\n    ctx.restore();\n\n    const haze = ctx.createLinearGradient(0, 430, 0, H);\n    haze.addColorStop(0, \"rgba(255,241,201,0)\");\n    haze.addColorStop(1, \"rgba(207,209,255,.16)\");\n    ctx.fillStyle = haze;\n    ctx.fillRect(0, 420, W, H - 420);\n  }\n\n  function drawCloud(x, y, scale, color) {\n    ctx.save();\n    ctx.translate(x, y);\n    ctx.scale(scale, scale);\n    ctx.fillStyle = color;\n    ctx.beginPath();\n    ctx.arc(26, 19, 21, Math.PI, 0);\n    ctx.arc(55, 11, 30, Math.PI, 0);\n    ctx.arc(88, 20, 22, Math.PI, 0);\n    ctx.lineTo(105, 34);\n    ctx.lineTo(8, 34);\n    ctx.closePath();\n    ctx.fill();\n    ctx.restore();\n  }\n\n  function drawWorkshopSilhouette() {\n    const c = palette();\n    const y = 520;\n    const offset = (state.idleTime * 10) % 170;\n\n    ctx.fillStyle = \"rgba(35,20,47,.70)\";\n    ctx.fillRect(0, y + 50, W, 70);\n\n    for (let i = -1; i < 4; i++) {\n      const x = i * 170 - offset;\n      ctx.fillStyle = \"rgba(49,32,61,.82)\";\n      roundRect(x + 18, y + 18, 128, 78, 10);\n      ctx.fill();\n\n      ctx.beginPath();\n      ctx.moveTo(x + 8, y + 28);\n      ctx.lineTo(x + 82, y - 22);\n      ctx.lineTo(x + 156, y + 28);\n      ctx.closePath();\n      ctx.fill();\n\n      ctx.fillStyle = c.gold;\n      for (let w = 0; w < 3; w++) {\n        roundRect(x + 38 + w * 34, y + 44, 18, 24, 5);\n        ctx.fill();\n      }\n\n      ctx.fillStyle = c.wood;\n      roundRect(x + 70, y + 58, 24, 38, 5);\n      ctx.fill();\n\n      ctx.strokeStyle = \"rgba(244,197,66,.30)\";\n      ctx.lineWidth = 2;\n      ctx.beginPath();\n      ctx.moveTo(x + 18, y + 78);\n      ctx.lineTo(x + 146, y + 78);\n      ctx.stroke();\n    }\n  }\n\n  function drawHangingLanterns() {\n    const c = palette();\n    ctx.save();\n    ctx.strokeStyle = c.woodDark;\n    ctx.lineWidth = 8;\n    ctx.beginPath();\n    ctx.moveTo(-8, 16);\n    ctx.bezierCurveTo(92, 34, 250, 3, 370, 24);\n    ctx.stroke();\n\n    for (let i = 0; i < 5; i++) {\n      const x = 38 + i * 69;\n      const y = 50 + (i % 2) * 7;\n      ctx.strokeStyle = c.wood;\n      ctx.lineWidth = 1.4;\n      ctx.beginPath();\n      ctx.moveTo(x, 25);\n      ctx.lineTo(x, y - 8);\n      ctx.stroke();\n\n      const glow = ctx.createRadialGradient(x, y, 1, x, y, 19);\n      glow.addColorStop(0, \"rgba(255,248,231,.94)\");\n      glow.addColorStop(.42, \"rgba(244,197,66,.36)\");\n      glow.addColorStop(1, \"rgba(244,197,66,0)\");\n      ctx.fillStyle = glow;\n      ctx.beginPath();\n      ctx.arc(x, y, 19, 0, Math.PI * 2);\n      ctx.fill();\n\n      ctx.fillStyle = c.gold;\n      roundRect(x - 6, y - 7, 12, 14, 4);\n      ctx.fill();\n      ctx.strokeStyle = c.woodDark;\n      ctx.stroke();\n    }\n    ctx.restore();\n  }\n\n  function drawStarDust() {\n    const c = palette();\n    for (let i = 0; i < 38; i++) {\n      const px = (i * 47 + state.idleTime * (5 + i % 3)) % (W + 44) - 22;\n      const py = 78 + (i * 37 + Math.sin(state.idleTime * .72 + i) * 18) % 440;\n      const radius = 1 + (i % 4) * .36;\n      const alpha = .20 + Math.sin(state.idleTime * 2 + i) * .10;\n      ctx.fillStyle = i % 5 === 0 ? c.glow : \"rgba(255,248,231,\" + alpha + \")\";\n      ctx.beginPath();\n      ctx.arc(px, py, radius, 0, Math.PI * 2);\n      ctx.fill();\n    }\n  }\n\n  function drawMoonRabbit() {\n    if (!player) return;\n    const c = palette();\n\n    ctx.save();\n    const idleLift = mmfAnd(((!state.gameStarted || state.paused)), () => (!state.gameOver)) ? Math.sin(state.idleTime * 2.2) * 5 : 0;\n    ctx.translate(player.x, player.y + idleLift);\n    ctx.rotate(player.rotation * .13);\n\n    const wingSpread = 1 + Math.sin(player.wingBeat * 1.7) * .08 + player.flapStretch * .24;\n    const glow = ctx.createRadialGradient(0, 0, 2, 0, 0, 54 + state.shieldFlash * 40);\n    glow.addColorStop(0, state.shield ? \"rgba(255,248,231,.90)\" : \"rgba(244,197,66,.46)\");\n    glow.addColorStop(.58, state.shield ? \"rgba(207,209,255,.25)\" : \"rgba(244,197,66,.10)\");\n    glow.addColorStop(1, \"rgba(255,255,255,0)\");\n    ctx.fillStyle = glow;\n    ctx.beginPath();\n    ctx.arc(0, 0, 55 + state.shieldFlash * 20, 0, Math.PI * 2);\n    ctx.fill();\n\n    if (state.shield) {\n      ctx.strokeStyle = \"rgba(255,248,231,\" + (0.74 + state.shieldFlash * .16) + \")\";\n      ctx.lineWidth = 3;\n      ctx.beginPath();\n      ctx.arc(0, 0, 31 + Math.sin(state.time * 10) * 1.5, 0, Math.PI * 2);\n      ctx.stroke();\n      ctx.strokeStyle = \"rgba(244,197,66,.84)\";\n      ctx.lineWidth = 1.5;\n      ctx.beginPath();\n      ctx.arc(0, 0, 37 + Math.sin(state.time * 7) * 1.2, 0, Math.PI * 2);\n      ctx.stroke();\n    }\n\n    ctx.save();\n    ctx.scale(wingSpread, 1);\n    ctx.fillStyle = \"rgba(207,209,255,.90)\";\n    ctx.strokeStyle = \"rgba(244,197,66,.48)\";\n    ctx.lineWidth = 1.3;\n    ctx.beginPath();\n    ctx.moveTo(-7, -3);\n    ctx.bezierCurveTo(-31, -25, -46, -9, -38, 9);\n    ctx.bezierCurveTo(-31, 21, -18, 17, -5, 7);\n    ctx.closePath();\n    ctx.fill();\n    ctx.stroke();\n    ctx.beginPath();\n    ctx.moveTo(7, -3);\n    ctx.bezierCurveTo(31, -25, 46, -9, 38, 9);\n    ctx.bezierCurveTo(31, 21, 18, 17, 5, 7);\n    ctx.closePath();\n    ctx.fill();\n    ctx.stroke();\n    ctx.restore();\n\n    ctx.fillStyle = c.rose;\n    ctx.strokeStyle = c.woodDark;\n    ctx.lineWidth = 1.6;\n\n    ctx.beginPath();\n    ctx.ellipse(-7, -19, 6, 17, -.10, 0, Math.PI * 2);\n    ctx.ellipse(7, -19, 6, 17, .10, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n\n    ctx.fillStyle = \"rgba(255,248,231,.46)\";\n    ctx.beginPath();\n    ctx.ellipse(-7, -19, 2.5, 11, -.10, 0, Math.PI * 2);\n    ctx.ellipse(7, -19, 2.5, 11, .10, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.rose;\n    ctx.beginPath();\n    ctx.ellipse(0, 3, 16, 20, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n\n    ctx.fillStyle = c.ink;\n    ctx.beginPath();\n    ctx.arc(-5, 0, 1.7, 0, Math.PI * 2);\n    ctx.arc(5, 0, 1.7, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.ivory;\n    ctx.beginPath();\n    ctx.ellipse(0, 7, 3.5, 2.4, 0, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.violet;\n    roundRect(-15, 18, 30, 13, 4);\n    ctx.fill();\n    ctx.strokeStyle = c.woodDark;\n    ctx.stroke();\n\n    ctx.fillStyle = c.cream;\n    roundRect(-8, 20, 16, 7, 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.wood;\n    ctx.save();\n    ctx.translate(13, 24);\n    ctx.rotate(-.50);\n    roundRect(-2, -12, 5, 25, 2);\n    ctx.fill();\n    roundRect(-8, -14, 16, 8, 3);\n    ctx.fill();\n    ctx.restore();\n\n    if (player.sparkle > 0) {\n      for (let i = 0; i < 3; i++) {\n        const sx = -28 - i * 8;\n        const sy = 3 + Math.sin(state.time * 12 + i) * 2;\n        ctx.fillStyle = \"rgba(244,197,66,\" + Math.min(1, player.sparkle * 3) + \")\";\n        ctx.beginPath();\n        ctx.arc(sx, sy, 2.8, 0, Math.PI * 2);\n        ctx.fill();\n      }\n    }\n\n    ctx.restore();\n  }\n\n  function drawParticles() {\n    particles.forEach(function (particle) {\n      ctx.save();\n      ctx.globalAlpha = Math.max(0, particle.life \/ particle.maxLife);\n      ctx.translate(particle.x, particle.y);\n      ctx.rotate(particle.rotation);\n      ctx.fillStyle = particle.color;\n      if (particle.crumb) {\n        roundRect(-particle.radius, -particle.radius * .65, particle.radius * 2, particle.radius * 1.3, particle.radius * .45);\n        ctx.fill();\n      } else {\n        ctx.beginPath();\n        ctx.arc(0, 0, particle.radius, 0, Math.PI * 2);\n        ctx.fill();\n      }\n      ctx.restore();\n    });\n  }\n\n  function drawGate(gate) {\n    const topHeight = gate.gapY - gate.gapHeight \/ 2;\n    const bottomY = gate.gapY + gate.gapHeight \/ 2;\n\n    drawWorkshopGate(gate.x, -22, gate.width, topHeight + 22, true, gate.style);\n    drawWorkshopGate(gate.x, bottomY, gate.width, H - bottomY + 28, false, gate.style);\n\n    if (!gate.charm.collected) {\n      drawMoonCharm(gate.x + gate.charm.offsetX, gate.charm.y, gate.charm.radius, gate.charm.spin);\n    }\n\n    if (mmfAnd((gate.shieldItem), () => (!gate.shieldItem.collected))) {\n      drawMochiShield(gate.x + gate.shieldItem.offsetX, gate.shieldItem.y, gate.shieldItem.radius, gate.shieldItem.pulse);\n    }\n  }\n\n  function drawWorkshopGate(x, y, width, height, fromTop, style) {\n    const c = palette();\n    const bodyX = x + 5;\n    const bodyWidth = width - 10;\n    const themes = [\n      [c.plum, c.lavender, c.wood],\n      [c.wood, c.mochi, c.violet],\n      [c.violet, c.cloud, c.woodDark],\n      [c.woodDark, c.rose, c.plum]\n    ];\n    const theme = themes[style % themes.length];\n\n    const body = ctx.createLinearGradient(bodyX, y, bodyX + bodyWidth, y + height);\n    body.addColorStop(0, theme[0]);\n    body.addColorStop(.55, theme[1]);\n    body.addColorStop(1, theme[2]);\n    ctx.fillStyle = body;\n    roundRect(bodyX, y, bodyWidth, height, 10);\n    ctx.fill();\n    ctx.strokeStyle = \"rgba(255,241,201,.38)\";\n    ctx.lineWidth = 2;\n    ctx.stroke();\n\n    ctx.save();\n    roundRect(bodyX + 4, y + 4, bodyWidth - 8, Math.max(0, height - 8), 7);\n    ctx.clip();\n\n    for (let sy = y + 40; sy < y + height - 30; sy += 66) {\n      ctx.strokeStyle = \"rgba(255,241,201,.24)\";\n      ctx.lineWidth = 2;\n      ctx.beginPath();\n      ctx.moveTo(bodyX + 7, sy);\n      ctx.lineTo(bodyX + bodyWidth - 7, sy);\n      ctx.stroke();\n      drawMiniMochi(bodyX + bodyWidth \/ 2, sy - 10, Math.min(12, bodyWidth * .24), style);\n    }\n\n    for (let iy = y + 18; iy < y + height; iy += 74) {\n      ctx.fillStyle = \"rgba(255,248,231,.06)\";\n      ctx.beginPath();\n      ctx.arc(bodyX + 12, iy, 3, 0, Math.PI * 2);\n      ctx.arc(bodyX + bodyWidth - 12, iy + 20, 2.5, 0, Math.PI * 2);\n      ctx.fill();\n    }\n    ctx.restore();\n\n    drawGateCap(x, fromTop ? y + height - 31 : y, width, 31, fromTop);\n  }\n\n  function drawGateCap(x, y, width, height, fromTop) {\n    const c = palette();\n    const cap = ctx.createLinearGradient(0, y, 0, y + height);\n    cap.addColorStop(0, c.cream);\n    cap.addColorStop(.55, c.mochi);\n    cap.addColorStop(1, c.wood);\n    ctx.fillStyle = cap;\n    roundRect(x, y, width, height, 8);\n    ctx.fill();\n    ctx.strokeStyle = \"rgba(49,32,61,.50)\";\n    ctx.lineWidth = 1.5;\n    ctx.stroke();\n\n    const edge = fromTop ? y + height - 2 : y + 2;\n    for (let i = 0; i < 3; i++) {\n      const bx = x + width * (.25 + i * .25);\n      ctx.fillStyle = i === 1 ? c.rose : c.gold;\n      ctx.beginPath();\n      ctx.arc(bx, edge + (fromTop ? 7 : -7), 4.6, 0, Math.PI * 2);\n      ctx.fill();\n      ctx.strokeStyle = \"rgba(49,32,61,.22)\";\n      ctx.stroke();\n    }\n  }\n\n  function drawMiniMochi(x, y, radius, style) {\n    const c = palette();\n    ctx.save();\n    ctx.translate(x, y);\n    ctx.fillStyle = style % 2 ? c.cream : c.mochi;\n    ctx.strokeStyle = c.woodDark;\n    ctx.lineWidth = 1;\n    ctx.beginPath();\n    ctx.ellipse(0, 0, radius, radius * .65, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n    ctx.fillStyle = \"rgba(255,248,231,.42)\";\n    ctx.beginPath();\n    ctx.ellipse(-radius * .25, -radius * .18, radius * .24, radius * .16, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.restore();\n  }\n\n  function drawMoonCharm(x, y, radius, phase) {\n    const c = palette();\n    ctx.save();\n    ctx.translate(x, y + Math.sin(phase) * 4);\n    ctx.rotate(Math.sin(phase * .2) * .22);\n\n    const aura = ctx.createRadialGradient(0, 0, 1, 0, 0, radius * 5);\n    aura.addColorStop(0, \"rgba(255,248,231,.98)\");\n    aura.addColorStop(.32, \"rgba(244,197,66,.58)\");\n    aura.addColorStop(1, \"rgba(244,197,66,0)\");\n    ctx.fillStyle = aura;\n    ctx.beginPath();\n    ctx.arc(0, 0, radius * 4.8, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.gold;\n    ctx.beginPath();\n    ctx.arc(0, 0, 12, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.strokeStyle = c.woodDark;\n    ctx.lineWidth = 1.4;\n    ctx.stroke();\n\n    ctx.fillStyle = c.ivory;\n    ctx.beginPath();\n    ctx.arc(4, -2, 8, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.plum;\n    ctx.beginPath();\n    ctx.arc(-4, -1, 1.6, 0, Math.PI * 2);\n    ctx.arc(1, 2, 1.3, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.restore();\n  }\n\n  function drawMochiShield(x, y, radius, pulse) {\n    const c = palette();\n    ctx.save();\n    ctx.translate(x, y + Math.sin(pulse) * 4);\n\n    const aura = ctx.createRadialGradient(0, 0, 1, 0, 0, radius * 5.8);\n    aura.addColorStop(0, \"rgba(255,248,231,.96)\");\n    aura.addColorStop(.34, \"rgba(207,209,255,.48)\");\n    aura.addColorStop(1, \"rgba(207,209,255,0)\");\n    ctx.fillStyle = aura;\n    ctx.beginPath();\n    ctx.arc(0, 0, radius * 5.2, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.fillStyle = c.mochi;\n    ctx.strokeStyle = c.cream;\n    ctx.lineWidth = 2;\n    ctx.beginPath();\n    ctx.ellipse(0, 1, radius, radius * .82, 0, 0, Math.PI * 2);\n    ctx.fill();\n    ctx.stroke();\n\n    ctx.fillStyle = c.ink;\n    ctx.beginPath();\n    ctx.arc(-4, 0, 1.5, 0, Math.PI * 2);\n    ctx.arc(4, 0, 1.5, 0, Math.PI * 2);\n    ctx.fill();\n\n    ctx.strokeStyle = c.woodDark;\n    ctx.lineWidth = 1;\n    ctx.beginPath();\n    ctx.arc(0, 4, 3, .25, Math.PI - .25);\n    ctx.stroke();\n    ctx.restore();\n  }\n\n  function handlePrimaryAction() {\n    if (state.screen === \"pause\") resumeGame();\n    else startGame();\n  }\n\n  function handleSecondaryAction() {\n    startGame();\n  }\n\n  function isFullscreenActive() {\n    return document.fullscreenElement === root || document.webkitFullscreenElement === root;\n  }\n\n  function enterFallbackFullscreen() {\n    fallbackFullscreen = true;\n    root.classList.add(\"mmf-fullscreen-fallback\");\n    document.documentElement.classList.add(\"mmf-page-lock\");\n    if (document.body) document.body.classList.add(\"mmf-page-lock\");\n    scheduleFullscreenResize();\n  }\n\n  function exitFallbackFullscreen() {\n    fallbackFullscreen = false;\n    root.classList.remove(\"mmf-fullscreen-fallback\");\n    document.documentElement.classList.remove(\"mmf-page-lock\");\n    if (document.body) document.body.classList.remove(\"mmf-page-lock\");\n    scheduleFullscreenResize();\n  }\n\n  function toggleFullscreen() {\n    if (isFullscreenActive()) {\n      const exit = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen;\n      if (exit) {\n        try {\n          const result = exit.call(document);\n          if (mmfAnd((result), () => (typeof result.catch === \"function\"))) result.catch(function () {});\n        } catch (error) {}\n      }\n      return;\n    }\n\n    if (fallbackFullscreen) {\n      exitFallbackFullscreen();\n      return;\n    }\n\n    const request = root.requestFullscreen || root.webkitRequestFullscreen || root.mozRequestFullScreen || root.msRequestFullscreen;\n    if (!request) {\n      enterFallbackFullscreen();\n      return;\n    }\n\n    try {\n      const result = request.call(root);\n      if (mmfAnd((result), () => (typeof result.catch === \"function\"))) {\n        result.catch(function () {\n          enterFallbackFullscreen();\n        });\n      }\n    } catch (error) {\n      enterFallbackFullscreen();\n    }\n    scheduleFullscreenResize();\n  }\n\n  function scheduleFullscreenResize() {\n    [0, 80, 220, 420].forEach(function (delay) {\n      setTimeout(queueResize, delay);\n    });\n  }\n\n  function handleTapAction() {\n    if (modal.classList.contains(\"mmf-show\")) return;\n    if (state.paused || state.gameOver) return;\n    if (!state.gameStarted) {\n      startGame();\n      return;\n    }\n    flap(false);\n  }\n\n  function onPointerDown(event) {\n    if (event.target.closest(\"button\")) return;\n    event.preventDefault();\n    try { root.focus({ preventScroll: true }); } catch (ignore) { root.focus(); }\n    handleTapAction();\n  }\n\n  function onKeyDown(event) {\n    if (!root.contains(document.activeElement)) {\n      if (!isFullscreenActive()) {\n        if (!fallbackFullscreen) return;\n      }\n    }\n    if (event.altKey || event.ctrlKey || event.metaKey) return;\n    if (event.target) {\n      if (event.target.closest) {\n        if (event.target.closest('input, textarea, select, [contenteditable=\"true\"]')) return;\n      }\n    }\n    if (event.code === \"Space\" || event.code === \"ArrowUp\") {\n      event.preventDefault();\n      if (state.screen === \"pause\") resumeGame();\n      else if (mmfAnd((mmfAnd((modal.classList.contains(\"mmf-show\")), () => (!state.gameOver))), () => (!state.gameStarted))) startGame();\n      else handleTapAction();\n    } else if (event.code === \"KeyP\") {\n      event.preventDefault();\n      if (state.paused) resumeGame();\n      else if (mmfAnd((state.gameStarted), () => (!state.gameOver))) pauseGame();\n    }\n  }\n\n  function togglePause() {\n    if (mmfAnd((!state.gameStarted), () => (!state.paused))) return;\n    if (state.paused) resumeGame();\n    else if (!state.gameOver) pauseGame();\n  }\n\n  function gameLoop(now) {\n    const deltaTime = Math.max(0, Math.min(.035, (now - lastTime) \/ 1000));\n    lastTime = now;\n    if (gameInView) {\n      update(deltaTime);\n      draw();\n    }\n    requestAnimationFrame(gameLoop);\n  }\n\n  function bindEvents() {\n    stage.addEventListener(\"pointerdown\", onPointerDown, { passive: false });\n    stage.addEventListener(\"touchstart\", function (event) {\n      if (!event.target.closest(\"button\")) event.preventDefault();\n    }, { passive: false });\n    document.addEventListener(\"keydown\", onKeyDown);\n\n    primaryButton.addEventListener(\"click\", handlePrimaryAction);\n    secondaryButton.addEventListener(\"click\", handleSecondaryAction);\n\n    pauseButton.addEventListener(\"click\", function (event) {\n      event.stopPropagation();\n      togglePause();\n    });\n\n    soundButton.addEventListener(\"click\", function (event) {\n      event.stopPropagation();\n      state.muted = !state.muted;\n      writeStorage(MUTE_KEY, state.muted ? \"1\" : \"0\");\n      syncInterface();\n      if (!state.muted) playSound(\"resume\");\n    });\n\n    fullscreenButton.addEventListener(\"click\", function (event) {\n      event.stopPropagation();\n      toggleFullscreen();\n    });\n\n    function fullscreenChanged() {\n      if (isFullscreenActive()) {\n        fallbackFullscreen = false;\n        root.classList.remove(\"mmf-fullscreen-fallback\");\n        document.documentElement.classList.remove(\"mmf-page-lock\");\n        if (document.body) document.body.classList.remove(\"mmf-page-lock\");\n      }\n      scheduleFullscreenResize();\n    }\n\n    document.addEventListener(\"fullscreenchange\", fullscreenChanged);\n    document.addEventListener(\"webkitfullscreenchange\", fullscreenChanged);\n    document.addEventListener(\"mozfullscreenchange\", fullscreenChanged);\n    document.addEventListener(\"MSFullscreenChange\", fullscreenChanged);\n\n    document.addEventListener(\"keydown\", function (event) {\n      if (mmfAnd((event.key === \"Escape\"), () => (fallbackFullscreen))) exitFallbackFullscreen();\n    });\n\n    window.addEventListener(\"resize\", queueResize, { passive: true });\n    window.addEventListener(\"orientationchange\", function () {\n      setTimeout(scheduleFullscreenResize, 180);\n    }, { passive: true });\n\n    if (window.visualViewport) {\n      window.visualViewport.addEventListener(\"resize\", queueResize, { passive: true });\n    }\n\n    if (window.ResizeObserver) {\n      const gameResizeObserver = new ResizeObserver(queueResize);\n      gameResizeObserver.observe(root);\n    }\n\n    if (window.IntersectionObserver) {\n      const gameVisibility = new IntersectionObserver(function (entries) {\n        gameInView = entries[0].isIntersecting;\n        if (!gameInView) {\n          if (state.gameStarted) {\n            if (!state.paused) pauseGame();\n          }\n        } else {\n          lastTime = performance.now();\n          draw();\n        }\n      }, { threshold: 0.01 });\n      gameVisibility.observe(root);\n    }\n\n    document.addEventListener(\"visibilitychange\", function () {\n      if (mmfAnd((mmfAnd((mmfAnd((document.hidden), () => (state.gameStarted))), () => (!state.paused))), () => (!state.gameOver))) pauseGame();\n    });\n  }\n\n  resetGame();\n  showModal(\"start\");\n  syncInterface();\n  bindEvents();\n  resizeCanvas();\n  requestAnimationFrame(gameLoop);\n})();\n<\/script>\n\n\n\n<h2 class=\"wp-block-heading\">Simple Controls with Precise Timing<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mochiwing Moonflight is designed to be immediately playable. On a touchscreen, tapping the game area causes the courier to flap upward. Desktop players can click with the mouse or press the Space key or Up Arrow. Between each flap, gravity pulls the rabbit downward, creating a smooth rising-and-falling movement that players must carefully control.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The most important skill is rhythm. Tapping too quickly may send the courier into an upper workshop shelf, while waiting too long can cause the rabbit to fall into the lower obstacles. Each opening requires a different approach depending on its height, distance, and the courier\u2019s current momentum. Successful players learn to use small, controlled flaps rather than reacting with hurried movements.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The first few passages provide enough room to understand the flying pattern. As the score grows, the route gradually becomes faster and the gaps become more demanding. The challenge increases naturally without changing the basic control system, allowing both new and experienced players to improve through practice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Workshop Gates and Moonlit Obstacles<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The route through the Moon Rabbit Workshop is filled with structures that connect the floating workrooms. Tall storage racks extend from both the ceiling and the lower platforms, leaving a single passage through which the courier must fly. These obstacles are decorated with small tools, wooden panels, mochi trays, lunar ornaments, and handmade details that connect them to the workshop\u2019s story.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the obstacles reach both the top and bottom edges of the playing area, players cannot escape by flying around them. Every gate must be crossed through its open center. The position of each opening changes, requiring constant attention and preventing the flight from becoming repetitive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The route also becomes faster over time. A passage that appears comfortable from a distance can quickly approach the courier, so players must look ahead rather than focus only on the character. This creates a satisfying balance between calm visual presentation and increasingly focused gameplay.<\/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 float inside many of the open passages. These small glowing tokens contain fragments of energy used throughout the workshop. Collecting one rewards additional points and creates a brief burst of light around the courier.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The charms are usually placed within a safe route, but reaching them may require more precise positioning. Players must decide whether to follow the easiest line through an obstacle or adjust their flight to collect the charm. This adds a small layer of risk and reward to each passage.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Moon Charms are more than ordinary collectibles within the game\u2019s story. Each one carries a tiny instruction from the workshop\u2019s master craftsmen. When enough charms return to the workshop, the rabbits can restore damaged lanterns, repair cloudy pathways, and keep the night sky from slowly fading.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Mochi Moon Shield<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">During the journey, players may discover a Mochi Moon Shield. This rare protective item surrounds the courier with a soft lunar barrier and allows the rabbit to survive one collision.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When the protected courier touches an obstacle, the shield breaks with a gentle burst of glowing fragments. The rabbit is pushed away from danger and the flight continues. This gives the player a valuable second chance without removing the challenge entirely. Once the barrier has been used, another collision will end the current journey unless a new shield is collected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The shield is particularly useful later in the game when the route becomes faster and the openings become narrower. However, it should not encourage careless flying. Skilled players treat it as emergency protection while continuing to follow the safest path through the workshop.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Score, Distance, and Personal Records<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Players earn points by successfully passing workshop gates and collecting Moon Charms. Every completed passage represents another successful delivery checkpoint, while collected charms provide an additional score bonus.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The current score is displayed clearly at the top of the screen. The game also remembers the player\u2019s best result in the browser, creating a simple long-term goal. Each new attempt becomes an opportunity to travel farther, collect more charms, and improve the previous record.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is no fixed final level. Mochiwing Moonflight is an endless journey that continues until the courier collides with an obstacle or falls outside the safe route. This structure makes the game suitable for short sessions while still offering a challenge that can be revisited many times.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Cozy World with a Growing Challenge<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The visual direction of Mochiwing Moonflight combines deep plum skies, dusty lavender clouds, warm wooden tools, creamy moonlight, and soft golden highlights. The world feels handmade rather than mechanical. Shelves, charms, gates, and decorations appear as though they were carefully assembled by the rabbits inside the workshop.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Although the atmosphere is gentle, the gameplay becomes increasingly demanding. The contrast between the peaceful setting and the focused flying challenge gives the game its distinctive personality. Players can enjoy the soft colors and small environmental details while still working toward a higher score.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Short sound effects accompany flaps, collected charms, activated shields, collisions, and score milestones. The sounds are intentionally brief and light so they support the game without overwhelming the quiet mood. Sound can be turned off at any time using the speaker button.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Designed for Desktop and Mobile Play<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Mochiwing Moonflight is built for modern browsers and adapts to desktop computers, tablets, and smartphones. Its portrait layout gives the flying route enough vertical space while keeping the controls easy to reach on smaller screens.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game includes pause, sound, and fullscreen controls. Fullscreen mode enlarges the workshop while preserving the portrait playing area and keeping it centered on the display. On mobile devices, touch input allows the entire game area to act as a flight control. Desktop players can use the mouse or keyboard without changing the core experience.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The compact interface keeps attention on the route. Important information remains visible, but the screen is not filled with unnecessary menus or complicated settings. A player can begin a new flight within seconds.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Meaning Behind Every Flight<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At its heart, Mochiwing Moonflight is a story about a small apprentice accepting a responsibility that appears larger than the rabbit\u2019s tiny wings. Every gate crossed represents another moment of confidence. Every Moon Charm collected helps restore the workshop. Every broken shield shows that mistakes do not always have to end the journey.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The game does not ask players to defeat an enemy or conquer the night. Instead, it asks them to keep moving through uncertainty, one careful flap at a time. The route becomes faster, the spaces become narrower, and the pressure grows, but the warm light of the workshop remains in the distance.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Guide the moon rabbit through the hanging racks, gather the scattered charms, protect the precious delivery, and help the Moon Rabbit Workshop keep its promises to the night sky. The next passage is already approaching, and somewhere beyond the clouds, another lantern is waiting to be lit.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mochiwing Moonflight is a cozy endless flying game set high above the sleeping world, where moonlit clouds drift around a secret workshop operated by tiny celestial rabbits. In this magical place, every lantern, charm, wooden tool, and piece of mochi is carefully crafted to keep the night sky glowing. Players guide a young moon rabbit &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-78","post","type-post","status-publish","format-standard","hentry","category-casual"],"_links":{"self":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/posts\/78","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=78"}],"version-history":[{"count":0,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=\/wp\/v2\/posts\/78\/revisions"}],"wp:attachment":[{"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=78"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=78"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/play.produsenpagarbrc.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=78"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}