{"id":92501,"date":"2025-12-05T03:42:55","date_gmt":"2025-12-05T03:42:55","guid":{"rendered":"https:\/\/gl-open.com\/?post_type=glopen_product&#038;p=92501"},"modified":"2026-01-15T06:09:43","modified_gmt":"2026-01-15T06:09:43","slug":"shanghai-walking-tour","status":"publish","type":"glopen_product","link":"https:\/\/gl-open.com\/day-tour-product\/shanghai-walking-tour\/","title":{"rendered":"3-Hour Old Shanghai Walking Tour in Shanghai"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; custom_margin=&#8221;||2rem||false|false&#8221; custom_padding=&#8221;0px||0px||true|false&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_row use_custom_gutter=&#8221;on&#8221; gutter_width=&#8221;2&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; width=&#8221;100%&#8221; max_width=&#8221;unset&#8221; custom_padding=&#8221;0px||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_gallery gallery_ids=&#8221;92498,92497,92496,92494,92495,92493,92492,92491&#8243; show_title_and_caption=&#8221;off&#8221; show_pagination=&#8221;off&#8221; zoom_icon_color=&#8221;RGBA(255,255,255,0)&#8221; hover_overlay_color=&#8221;RGBA(255,255,255,0)&#8221; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; width=&#8221;100%&#8221; global_colors_info=&#8221;{}&#8221;][\/et_pb_gallery][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; custom_padding=&#8221;0px|0px|0px|0px|false|false&#8221; custom_css_free_form=&#8221;\/* \u5168\u5c40 *\/||.container {||  max-width: 1280px;||}||h1.entry-title {||  color: #AD9264;||  font-size: 2.25rem !important;||  font-weight: 700;||  margin-bottom: 1rem;||}||||selector p {||  font-size: 1rem !important;||  line-height: 1.5 !important;||  font-weight: 400;||}||selector ul:last-child {||  padding-bottom:0 !important;||}||selector li {||  font-weight: 400;||}||selector h2 {||  font-size: 1.75rem !important;||  font-weight: 600 !important;||  color: #304d73 !important;||}||||\/* \u5207\u6362\u56fe\u6807 *\/||.et-db #et-boc .et-l .et_pb_toggle_title:before,||.et-db #et-boc .et-l .et_pb_toggle_title:after {||  font-size: 35px !important;||  right: -8px !important;||}&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_row column_structure=&#8221;2_3,1_3&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; width=&#8221;100%&#8221; max_width=&#8221;unset&#8221; custom_padding=&#8221;0px|0px|0px|0px|false|false&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;2_3&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_heading title=&#8221;Overview&#8221; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; title_text_color=&#8221;#304d73&#8243; custom_margin=&#8221;||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][\/et_pb_heading][et_pb_text _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;_initial&#8221; text_font=&#8221;||||||||&#8221; text_text_color=&#8221;#000000&#8243; text_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||1rem||false|false&#8221; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p>Experience the heart of Old Shanghai on a guided walk through its most historic streets. You\u2019ll explore the peaceful paths of Yu Garden, wander lively bazaars filled with local life, and visit a centuries-old mosque and Taoist temple. The tour ends at the city\u2019s last ancient wall, where the past meets the modern skyline. It\u2019s an easy, enriching experience for culture lovers and curious travelers.<\/p>\n<p>[\/et_pb_text][dipl_list icon_font_size=&#8221;1.25em&#8221; icon_width=&#8221;1.25em&#8221; icon_color=&#8221;#c4b293&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; item_name_font=&#8221;||||||||&#8221; item_name_text_color=&#8221;#000000&#8243; item_name_font_size=&#8221;1rem&#8221; item_name_line_height=&#8221;2em&#8221; custom_margin=&#8221;||||false|false&#8221; custom_css_free_form=&#8221;selector .dipl-list-item-wrap {||  display: flex;||  align-items: center;||}||selector .dipl_list-item_text {||  font-weight: 400;||}&#8221; global_colors_info=&#8221;{}&#8221;][dipl_list_item item_name=&#8221;Duration: 3 hours&#8221; icon=&#8221;&#xf1da;||fa||900&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; custom_margin=&#8221;||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][\/dipl_list_item][dipl_list_item item_name=&#8221;Language: English&#8221; icon=&#8221;&#xe0e3;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; custom_margin=&#8221;||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][\/dipl_list_item][dipl_list_item item_name=&#8221;Ages 0-99&#8243; icon=&#8221;&#xf007;||fa||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; custom_margin=&#8221;||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][\/dipl_list_item][\/dipl_list][et_pb_toggle title=&#8221;Highlights&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; hover_transition_duration=&#8221;0ms&#8221; hover_transition_speed_curve=&#8221;ease-in&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<ul>\n<li data-v-9bd5fe4b=\"\">Explore Yu Garden\u2019s classical pavilions and tranquil walkways<\/li>\n<li data-v-9bd5fe4b=\"\">Wander through bustling bazaars filled with shops and local activity<\/li>\n<li data-v-9bd5fe4b=\"\">Visit a historic mosque that reflects Shanghai\u2019s diverse heritage<\/li>\n<li data-v-9bd5fe4b=\"\">Step inside Shanghai Baiyun Taoist Temple for a look at living tradition<\/li>\n<li data-v-9bd5fe4b=\"\">Stand before the city\u2019s last ancient wall and take in views of old and modern Shanghai<\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_toggle title=&#8221;What\u2019s Included&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<div>\n<ul>\n<li>Private English tour guide<\/li>\n<li>Bottled water<\/li>\n<li>Entry\/Admission &#8211; Yu Garden (Yuyuan)<\/li>\n<\/ul>\n<\/div>\n<h2><\/h2>\n<h2><\/h2>\n<h2>What\u2019s Not Included<\/h2>\n<ul>\n<li><span>Personal expenses<\/span><\/li>\n<li><span>Transportation to and from the meeting point<\/span><\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_toggle title=&#8221;Meeting Point&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; custom_css_free_form=&#8221;selector ul:last-of-type {||  padding-bottom:.5rem !important;||}||selector .tomaps {||  color: #000;||  text-decoration: underline;||  font-weight:600;||}&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p><strong>Start:<\/strong><\/p>\n<ul>\n<li>\n<div data-zone-id=\"0\" data-line-index=\"0\" data-line=\"true\">McDonald\u2019s, 88 Lishui Road, Yuyuan, Huangpu District, Shanghai, China<\/div>\n<\/li>\n<\/ul>\n<p><a href=\"https:\/\/maps.app.goo.gl\/Ya3ZYdNuoV9rt5cw7\" target=\"_blank\" class=\"tomaps\" rel=\"noopener\">Open in Google Maps<\/a><\/p>\n<p><strong>End:<\/strong><\/p>\n<ul>\n<li>This activity ends back at the meeting point.<\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_toggle title=&#8221;Public Transportation&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; custom_css_free_form=&#8221;selector ul:last-of-type {||  padding-bottom:.5rem !important;||}||selector .tomaps {||  color: #000;||  text-decoration: underline;||  font-weight:600;||}&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<ul>\n<li>Subway: Take Line 10 or Line 14 to Yuyuan Garden Station.<\/li>\n<li>Exit at Exit 1, 5, or 7.Walk about 8\u201310 minutes (600\u2013700m) along Fuyou Road, then turn to Lishui Road.<\/li>\n<li>Didi: &#8220;McDonald\u2019s, 88 Lishui Road, Yuyuan, Huangpu District.&#8221;<\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_toggle title=&#8221;Cancellation Policy&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; custom_css_free_form=&#8221;selector ul:last-child {||  padding-bottom:0 !important;||}&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<ul>\n<li>For a full refund, cancel at least 24 hours before your experience begins.<\/li>\n<li>Cancellations made within 24 hours of the start time are non-refundable.<\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_toggle title=&#8221;Accessibility&#8221; open=&#8221;on&#8221; open_toggle_text_color=&#8221;#304d73&#8243; open_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; closed_toggle_text_color=&#8221;#304d73&#8243; closed_toggle_background_color=&#8221;RGBA(255,255,255,0)&#8221; icon_color=&#8221;#304d73&#8243; toggle_icon=&#8221;&#x32;||divi||400&#8243; open_icon_color=&#8221;#304d73&#8243; open_toggle_icon=&#8221;&#x33;||divi||400&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_text_color=&#8221;#304d73&#8243; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1rem&#8221; custom_margin=&#8221;||0px||false|false&#8221; custom_padding=&#8221;|0px||0px|false|false&#8221; custom_css_free_form=&#8221;selector ul:last-child {||  padding-bottom:0 !important;||}&#8221; border_width_all=&#8221;0px&#8221; border_color_all=&#8221;RGBA(255,255,255,0)&#8221; border_width_top=&#8221;2px&#8221; border_color_top=&#8221;#000000&#8243; global_colors_info=&#8221;{}&#8221;]<\/p>\n<ul>\n<li>Not wheelchair accessible<\/li>\n<li>Near public transportation<\/li>\n<\/ul>\n<p>[\/et_pb_toggle][et_pb_heading title=&#8221;Other China Day Tours You Might Like&#8221; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; title_level=&#8221;h2&#8243; title_font=&#8221;|700|||||||&#8221; title_text_color=&#8221;#304d73&#8243; custom_margin=&#8221;||0px||false|false&#8221; global_colors_info=&#8221;{}&#8221;][\/et_pb_heading][et_pb_code _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;]<div class=\"glopen-products-container\"><div class=\"glopen-products-grid\"><div class=\"glopen-product-card\"><div class=\"glopen-product-image\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-tea-ceremony-shanghai\/\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"480\" src=\"https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/6f-1.jpg\" class=\"glopen-product-thumbnail wp-post-image\" alt=\"\" srcset=\"https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/6f-1.jpg 720w, https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/6f-1-480x320.jpg 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 720px, 100vw\" \/><\/a><\/div><div class=\"glopen-product-tips\"><span>Shanghai<\/span><span>Indoor<\/span><\/div><div class=\"glopen-product-title\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-tea-ceremony-shanghai\/\">3-Hour Chinese Tea Ceremony in Shanghai<\/a><\/div><div class=\"glopen-product-excerpt\">Experience authentic tea culture with hands-on brewing and serene ambiance.<\/div><div class=\"glopen-product-price\">from <strong>$111<\/strong> per person<\/div><div class=\"glopen-product-book\"><a href=\"https:\/\/www.tripadvisor.com\/AttractionProductReview-g308272-d33039019-Chinese_Tea_Ceremony_Experience-Shanghai.html\" target=\"_blank\" rel=\"noopener\">Book Now<\/a><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-tea-ceremony-shanghai\/\">Book Now<\/a><\/div><\/div><div class=\"glopen-product-card\"><div class=\"glopen-product-image\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-calligraphy-workshop-shanghai\/\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"480\" src=\"https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/chinese-calligraphy-worksho.jpg\" class=\"glopen-product-thumbnail wp-post-image\" alt=\"\" srcset=\"https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/chinese-calligraphy-worksho.jpg 720w, https:\/\/gl-open.com\/wp-content\/uploads\/2019\/07\/chinese-calligraphy-worksho-480x320.jpg 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 720px, 100vw\" \/><\/a><\/div><div class=\"glopen-product-tips\"><span>Shanghai<\/span><span>Indoor<\/span><\/div><div class=\"glopen-product-title\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-calligraphy-workshop-shanghai\/\">3-Hour Chinese Calligraphy Workshop in Shanghai<\/a><\/div><div class=\"glopen-product-excerpt\">Discover Chinese calligraphy and create your own personalized character artwork.<\/div><div class=\"glopen-product-price\">from <strong>$95<\/strong> per person<\/div><div class=\"glopen-product-book\"><a href=\"https:\/\/www.tripadvisor.com\/AttractionProductReview-g308272-d33350861-Chinese_Calligraphy_Workshop_From_Ancient_Scripts_to_Badges-Shanghai.html\" target=\"_blank\" rel=\"noopener\">Book Now<\/a><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-calligraphy-workshop-shanghai\/\">Book Now<\/a><\/div><\/div><div class=\"glopen-product-card\"><div class=\"glopen-product-image\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-painting-workshop-shanghai\/\"><img loading=\"lazy\" decoding=\"async\" width=\"720\" height=\"480\" src=\"https:\/\/gl-open.com\/wp-content\/uploads\/2025\/10\/chinese-painting-master-working.webp\" class=\"glopen-product-thumbnail wp-post-image\" alt=\"\" srcset=\"https:\/\/gl-open.com\/wp-content\/uploads\/2025\/10\/chinese-painting-master-working.webp 720w, https:\/\/gl-open.com\/wp-content\/uploads\/2025\/10\/chinese-painting-master-working-480x320.webp 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 720px, 100vw\" \/><\/a><\/div><div class=\"glopen-product-tips\"><span>Shanghai<\/span><span>Indoor<\/span><\/div><div class=\"glopen-product-title\"><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-painting-workshop-shanghai\/\">4-Hour Chinese Painting Workshop in Shanghai<\/a><\/div><div class=\"glopen-product-excerpt\">Create your own masterpiece in a guided Chinese painting session.<\/div><div class=\"glopen-product-price\">from <strong>$95<\/strong> per person<\/div><div class=\"glopen-product-book\"><a href=\"https:\/\/www.tripadvisor.com\/AttractionProductReview-g308272-d33370371-Shanghai_Traditional_Chinese_Painting_experience_Workshop-Shanghai.html\" target=\"_blank\" rel=\"noopener\">Book Now<\/a><a href=\"https:\/\/gl-open.com\/day-tour-product\/chinese-painting-workshop-shanghai\/\">Book Now<\/a><\/div><\/div><\/div><\/div>[\/et_pb_code][et_pb_code _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;]        <div class=\"glopen-product-reviews\">\n            <div class=\"glopen-reviews-list\">\n                                    <p class=\"glopen-no-reviews\">No reviews yet<\/p>\n                            <\/div>\n            \n                        \n            <!-- Image lightbox overlay -->\n            <div id=\"glopen-review-image-lightbox\" class=\"glopen-lightbox\">\n                <div class=\"glopen-lightbox-content\">\n                    <span class=\"glopen-lightbox-close\">&times;<\/span>\n                    <img decoding=\"async\" class=\"glopen-lightbox-img\" src=\"\" alt=\"Review Image\">\n                <\/div>\n            <\/div>\n            \n            <style>\n                .glopen-review-item {\n                    padding-bottom: 1rem;\n                    margin-bottom: 1rem;\n                    border-bottom: 1px solid #eee;\n                    display: flex;\n                    flex-direction: column;\n                    gap: .25rem;\n                }\n                .glopen-review-item:last-child {\n                    border-bottom: none;\n                    margin-bottom: 0;\n                    padding-bottom: 0;\n                }\n                .glopen-review-date {\n                    color: #999;\n                    font-size: 0.9rem;\n                }\n                .glopen-review-rating {\n                    font-size: 0;\n                    height: 1.5rem;\n                }\n                .glopen-review-rating span {\n                    display: inline-block;\n                    width: 1.5rem;\n                    height: 1.5rem;\n                    background-repeat: no-repeat;\n                }\n                .glopen-review-rating .star {\n                    background-image: url('data:image\/svg+xml;utf8,<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 24 24\" fill=\"%23AD9264\" stroke=\"%23AD9264\" stroke-width=\"2\" stroke-linejoin=\"round\"><polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"><\/polygon><\/svg>');\n                }\n                .glopen-review-rating .star:not(.filled) {\n                    background-image: url('data:image\/svg+xml;utf8,<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"%23ddd\" stroke-width=\"2\" stroke-linejoin=\"round\"><polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"><\/polygon><\/svg>');\n                }\n                .glopen-review-title {\n                    font-size: 1rem;\n                    font-weight: 500;\n                    color: #000;\n                    padding-bottom: 0;\n                }\n                .glopen-review-content {\n                    color: #555;\n                }\n                .glopen-review-content p {\n                    font-size: 1rem !important;\n                    font-size: 1rem !important;\n                    font-weight: 400;\n                    line-height: 1.25rem !important;\n                }\n                .glopen-review-images {\n                    display: flex;\n                    gap: 0.5rem;\n                    flex-wrap: wrap;\n                }\n                .glopen-review-image {\n                    width: 80px;\n                    height: 80px;\n                    object-fit: cover;\n                    border-radius: 4px;\n                    cursor: pointer;\n                    transition: transform 0.2s;\n                }\n                .glopen-review-image:hover {\n                    transform: scale(1.02);\n                }\n                .glopen-no-reviews {\n                    text-align: center;\n                    color: #999;\n                    padding: 2rem 0;\n                }\n                .glopen-reviews-load-more {\n                    margin-top: 1rem;\n                }\n                #glopen-load-more-btn {\n                    color: #000;\n                    border: none;\n                    padding: 0;\n                    text-decoration: underline;\n                    background: none;\n                    cursor: pointer;\n                    font-size: 1.25rem;\n                    font-weight: 600;\n                }\n                #glopen-load-more-btn:disabled {\n                    cursor: not-allowed;\n                    color: #555;\n                }\n                \n                \/* Lightbox styles *\/\n                .glopen-lightbox {\n                    display: none;\n                    position: fixed;\n                    z-index: 9999;\n                    left: 0;\n                    top: 0;\n                    width: 100%;\n                    height: 100%;\n                    overflow: auto;\n                    background-color: rgba(0, 0, 0, 0.9);\n                }\n                .glopen-lightbox-content {\n                    margin: auto;\n                    display: block;\n                    max-width: 90%;\n                    max-height: 90%;\n                    position: absolute;\n                    top: 50%;\n                    left: 50%;\n                    transform: translate(-50%, -50%);\n                }\n                .glopen-lightbox-img {\n                    width: auto;\n                    height: auto;\n                    max-width: 100%;\n                    max-height: 80vh;\n                }\n                .glopen-lightbox-close {\n                    position: absolute;\n                    top: 15px;\n                    right: 35px;\n                    color: #f1f1f1;\n                    font-size: 40px;\n                    font-weight: bold;\n                    transition: 0.3s;\n                    cursor: pointer;\n                }\n                .glopen-lightbox-close:hover {\n                    color: #bbb;\n                }\n            <\/style>\n            \n            <script>\n                document.addEventListener('DOMContentLoaded', function() {\n                    \/\/ const loadMoreBtn = document.querySelector('.glopen-load-more-btn');\n                    const loadMoreBtn = document.getElementById('glopen-load-more-btn');\n                    const lightbox = document.getElementById('glopen-review-image-lightbox');\n                    const lightboxImg = document.querySelector('.glopen-lightbox-img');\n                    const lightboxClose = document.querySelector('.glopen-lightbox-close');\n                    \n                    \/\/ Load more reviews functionality\n                    if (loadMoreBtn) {\n                        loadMoreBtn.addEventListener('click', function() {\n                            const button = this;\n                            const productId = button.getAttribute('data-product-id');\n                            const count = button.getAttribute('data-count');\n                            const page = button.getAttribute('data-page');\n                            const showImages = button.getAttribute('data-show-images') === '1';\n                            const showRating = button.getAttribute('data-show-rating') === '1';\n                            const showDate = button.getAttribute('data-show-date') === '1';\n                            \n                            button.disabled = true;\n                            button.textContent = 'Loading...';\n                            \n                            const xhr = new XMLHttpRequest();\n                            xhr.open('POST', 'https:\/\/gl-open.com\/wp-admin\/admin-ajax.php', true);\n                            xhr.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded');\n                            \n                            xhr.onload = function() {\n                                if (xhr.status === 200) {\n                                    try {\n                                        const response = JSON.parse(xhr.responseText);\n                                        if (response.success) {\n                                            const reviewsList = document.querySelector('.glopen-reviews-list');\n                                            reviewsList.insertAdjacentHTML('beforeend', response.data.html);\n                                            \n                                            \/\/ Update page number\n                                            const nextPage = parseInt(page) + 1;\n                                            button.setAttribute('data-page', nextPage);\n                                            \n                                            \/\/ Check if there are more reviews\n                                            if (!response.data.has_more) {\n                                                button.textContent = 'No more reviews';\n                                            }\n                                            \n                                            \/\/ Attach lightbox event to newly added images\n                                            attachLightboxEvents();\n                                        } else {\n                                            console.error('Failed to load reviews:', response.message);\n                                        }\n                                    } catch (e) {\n                                        console.error('Failed to parse response:', e);\n                                    }\n                                } else {\n                                    console.error('Request failed:', xhr.status);\n                                }\n                                \n                                if(button.textContent !== 'No more reviews'){\n                                    button.disabled = false;\n                                    button.textContent = 'Load More';\n                                }\n                            };\n                            \n                            xhr.onerror = function() {\n                                console.error('Network error');\n                                button.disabled = false;\n                                button.textContent = 'Load More';\n                            };\n                            \n                            xhr.send(`action=glopen_load_more_reviews&product_id=${productId}&count=${count}&page=${page}&show_images=${showImages ? 1 : 0}&show_rating=${showRating ? 1 : 0}&show_date=${showDate ? 1 : 0}`);\n                        });\n                    }\n                    \n                    \/\/ Lightbox functionality\n                    function attachLightboxEvents() {\n                        const reviewImages = document.querySelectorAll('.glopen-review-image');\n                        reviewImages.forEach(img => {\n                            img.addEventListener('click', function() {\n                                if (lightbox.parentNode !== document.body) {\n                                    if (lightbox.parentNode) {\n                                        lightbox.parentNode.removeChild(lightbox);\n                                    }\n                                    document.body.appendChild(lightbox);\n                                }\n                                document.body.style.overflow = 'hidden';\n                                lightbox.style.display = 'flex';\n                                lightboxImg.src = this.dataset.fullSize || this.src.replace('\/thumbnail\/', '\/fullsize\/');\n                            });\n                        });\n                    }\n                    \n                    \/\/ Initial attachment of lightbox events\n                    attachLightboxEvents();\n                    \n                    \/\/ Close lightbox when clicking on close button\n                    if (lightboxClose) {\n                        lightboxClose.addEventListener('click', function() {\n                            lightbox.style.display = 'none';\n                            document.body.style.overflow = 'auto';\n                        });\n                    }\n                    \n                    \/\/ Close lightbox when clicking outside the image\n                    if (lightbox) {\n                        lightbox.addEventListener('click', function(event) {\n                            if (event.target === lightbox) {\n                                lightbox.style.display = 'none';\n                                document.body.style.overflow = 'auto';\n                            }\n                        });\n                    }\n                    \n                    \/\/ Close lightbox with Escape key\n                    document.addEventListener('keydown', function(event) {\n                        if (event.key === 'Escape' && lightbox.style.display === 'flex') {\n                            lightbox.style.display = 'none';\n                            document.body.style.overflow = 'auto';\n                        }\n                    });\n                });\n            <\/script>\n        <\/div>\n        [\/et_pb_code][\/et_pb_column][et_pb_column type=&#8221;1_3&#8243; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_code _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; width=&#8221;100%&#8221; sticky_limit_top=&#8221;section&#8221; sticky_limit_bottom=&#8221;section&#8221; sticky_offset_surrounding_last_edited=&#8221;off|desktop&#8221; custom_css_free_form=&#8221;selector ul {||  list-style: none !important;||  padding-left: 0 !important;||  padding-bottom: 0 !important;||}||selector ul li:not(:last-of-type) {||  padding-bottom: 0 !important;||}||selector ul .glopen-booking-stitle {||  font-size: 1.25rem !important;||  padding-bottom: 1rem !important;||  font-weight: 500;||  color: #000;||}||selector ul .glopen-booking-spec-note {||  font-size: .75rem !important;||}&#8221; global_colors_info=&#8221;{}&#8221;]<div class=\"glopen-product-booking-container\"><div class=\"glopen-product-booking-header\"><div class=\"glopen-product-booking-price\"><span id=\"selected-price\">$ 207.00<\/span><\/div><p class=\"glopen-product-price-note\">per group (price varies by group size)<\/p><\/div><form id=\"glopen-booking-form\"><input type=\"hidden\" name=\"product_id\" value=\"91431\"><ul><li class=\"glopen-booking-section\"><p class=\"glopen-booking-stitle\">Number of Participants<\/p><div class=\"glopen-booking-spec-group\"><label class=\"glopen-spec-label\">Adults (Ages 13+)<\/label><div class=\"glopen-spec-options\"><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_0\" value=\"1 Adult\" ><span>1 Adult<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_0\" value=\"2 Adults\" ><span>2 Adults<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_0\" value=\"3 Adults\" ><span>3 Adults<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_0\" value=\"4 Adults\" ><span>4 Adults<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_0\" value=\"5 Adults\" ><span>5 Adults<\/span><\/label><\/div><\/div><div class=\"glopen-booking-spec-group\"><label class=\"glopen-spec-label\">Children (Ages 4-12)<\/label><div class=\"glopen-spec-options\"><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_1\" value=\"0 Child\" ><span>0 Child<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_1\" value=\"1 Child\" ><span>1 Child<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_1\" value=\"2 Children\" ><span>2 Children<\/span><\/label><label class=\"glopen-spec-option\"><input type=\"radio\" name=\"spec_1\" value=\"3 Children\" ><span>3 Children<\/span><\/label><\/div><\/div><p class=\"glopen-booking-spec-note\">* For groups of 7 or more, please <a href=\"mailto:travel-info@gl-open.com\">contact us<\/a>.<\/p><input type=\"hidden\" id=\"sales-attributes-json\" value=\"{&quot;selected_dates&quot;:{&quot;1-1&quot;:true,&quot;1-2&quot;:true,&quot;1-3&quot;:true,&quot;1-4&quot;:true,&quot;1-5&quot;:true,&quot;1-6&quot;:true,&quot;1-7&quot;:true,&quot;1-8&quot;:true,&quot;1-9&quot;:true,&quot;1-10&quot;:true,&quot;1-11&quot;:true,&quot;1-12&quot;:true,&quot;1-13&quot;:true,&quot;1-14&quot;:true,&quot;1-15&quot;:true,&quot;1-16&quot;:true,&quot;1-17&quot;:true,&quot;1-18&quot;:true,&quot;1-19&quot;:true,&quot;1-20&quot;:true,&quot;1-21&quot;:true,&quot;1-22&quot;:true,&quot;1-23&quot;:true,&quot;1-24&quot;:true,&quot;1-25&quot;:true,&quot;1-26&quot;:true,&quot;1-27&quot;:true,&quot;1-28&quot;:true,&quot;1-29&quot;:true,&quot;1-30&quot;:true,&quot;1-31&quot;:true,&quot;2-1&quot;:true,&quot;2-2&quot;:true,&quot;2-3&quot;:true,&quot;2-4&quot;:true,&quot;2-5&quot;:true,&quot;2-6&quot;:true,&quot;2-7&quot;:true,&quot;2-8&quot;:true,&quot;2-9&quot;:true,&quot;2-10&quot;:true,&quot;2-11&quot;:true,&quot;2-12&quot;:true,&quot;2-13&quot;:true,&quot;2-14&quot;:true,&quot;2-15&quot;:true,&quot;2-16&quot;:true,&quot;2-17&quot;:true,&quot;2-18&quot;:true,&quot;2-19&quot;:true,&quot;2-20&quot;:true,&quot;2-21&quot;:true,&quot;2-22&quot;:true,&quot;2-23&quot;:true,&quot;2-24&quot;:true,&quot;2-25&quot;:true,&quot;2-26&quot;:true,&quot;2-27&quot;:true,&quot;2-28&quot;:true,&quot;3-1&quot;:true,&quot;3-2&quot;:true,&quot;3-3&quot;:true,&quot;3-4&quot;:true,&quot;3-5&quot;:true,&quot;3-6&quot;:true,&quot;3-7&quot;:true,&quot;3-8&quot;:true,&quot;3-9&quot;:true,&quot;3-10&quot;:true,&quot;3-11&quot;:true,&quot;3-12&quot;:true,&quot;3-13&quot;:true,&quot;3-14&quot;:true,&quot;3-15&quot;:true,&quot;3-16&quot;:true,&quot;3-17&quot;:true,&quot;3-18&quot;:true,&quot;3-19&quot;:true,&quot;3-20&quot;:true,&quot;3-21&quot;:true,&quot;3-22&quot;:true,&quot;3-23&quot;:true,&quot;3-24&quot;:true,&quot;3-25&quot;:true,&quot;3-26&quot;:true,&quot;3-27&quot;:true,&quot;3-28&quot;:true,&quot;3-29&quot;:true,&quot;3-30&quot;:true,&quot;3-31&quot;:true,&quot;4-1&quot;:true,&quot;4-2&quot;:true,&quot;4-3&quot;:true,&quot;4-4&quot;:true,&quot;4-5&quot;:true,&quot;4-6&quot;:true,&quot;4-7&quot;:true,&quot;4-8&quot;:true,&quot;4-9&quot;:true,&quot;4-10&quot;:true,&quot;4-11&quot;:true,&quot;4-12&quot;:true,&quot;4-13&quot;:true,&quot;4-14&quot;:true,&quot;4-15&quot;:true,&quot;4-16&quot;:true,&quot;4-17&quot;:true,&quot;4-18&quot;:true,&quot;4-19&quot;:true,&quot;4-20&quot;:true,&quot;4-21&quot;:true,&quot;4-22&quot;:true,&quot;4-23&quot;:true,&quot;4-24&quot;:true,&quot;4-25&quot;:true,&quot;4-26&quot;:true,&quot;4-27&quot;:true,&quot;4-28&quot;:true,&quot;4-29&quot;:true,&quot;4-30&quot;:true,&quot;5-1&quot;:true,&quot;5-2&quot;:true,&quot;5-3&quot;:true,&quot;5-4&quot;:true,&quot;5-5&quot;:true,&quot;5-6&quot;:true,&quot;5-7&quot;:true,&quot;5-8&quot;:true,&quot;5-9&quot;:true,&quot;5-10&quot;:true,&quot;5-11&quot;:true,&quot;5-12&quot;:true,&quot;5-13&quot;:true,&quot;5-14&quot;:true,&quot;5-15&quot;:true,&quot;5-16&quot;:true,&quot;5-17&quot;:true,&quot;5-18&quot;:true,&quot;5-19&quot;:true,&quot;5-20&quot;:true,&quot;5-21&quot;:true,&quot;5-22&quot;:true,&quot;5-23&quot;:true,&quot;5-24&quot;:true,&quot;5-25&quot;:true,&quot;5-26&quot;:true,&quot;5-27&quot;:true,&quot;5-28&quot;:true,&quot;5-29&quot;:true,&quot;5-30&quot;:true,&quot;5-31&quot;:true,&quot;6-1&quot;:true,&quot;6-2&quot;:true,&quot;6-3&quot;:true,&quot;6-4&quot;:true,&quot;6-5&quot;:true,&quot;6-6&quot;:true,&quot;6-7&quot;:true,&quot;6-8&quot;:true,&quot;6-9&quot;:true,&quot;6-10&quot;:true,&quot;6-11&quot;:true,&quot;6-12&quot;:true,&quot;6-13&quot;:true,&quot;6-14&quot;:true,&quot;6-15&quot;:true,&quot;6-16&quot;:true,&quot;6-17&quot;:true,&quot;6-18&quot;:true,&quot;6-19&quot;:true,&quot;6-20&quot;:true,&quot;6-21&quot;:true,&quot;6-22&quot;:true,&quot;6-23&quot;:true,&quot;6-24&quot;:true,&quot;6-25&quot;:true,&quot;6-26&quot;:true,&quot;6-27&quot;:true,&quot;6-28&quot;:true,&quot;6-29&quot;:true,&quot;6-30&quot;:true,&quot;7-1&quot;:true,&quot;7-2&quot;:true,&quot;7-3&quot;:true,&quot;7-4&quot;:true,&quot;7-5&quot;:true,&quot;7-6&quot;:true,&quot;7-7&quot;:true,&quot;7-8&quot;:true,&quot;7-9&quot;:true,&quot;7-10&quot;:true,&quot;7-11&quot;:true,&quot;7-12&quot;:true,&quot;7-13&quot;:true,&quot;7-14&quot;:true,&quot;7-15&quot;:true,&quot;7-16&quot;:true,&quot;7-17&quot;:true,&quot;7-18&quot;:true,&quot;7-19&quot;:true,&quot;7-20&quot;:true,&quot;7-21&quot;:true,&quot;7-22&quot;:true,&quot;7-23&quot;:true,&quot;7-24&quot;:true,&quot;7-25&quot;:true,&quot;7-26&quot;:true,&quot;7-27&quot;:true,&quot;7-28&quot;:true,&quot;7-29&quot;:true,&quot;7-30&quot;:true,&quot;7-31&quot;:true,&quot;8-1&quot;:true,&quot;8-2&quot;:true,&quot;8-3&quot;:true,&quot;8-4&quot;:true,&quot;8-5&quot;:true,&quot;8-6&quot;:true,&quot;8-7&quot;:true,&quot;8-8&quot;:true,&quot;8-9&quot;:true,&quot;8-10&quot;:true,&quot;8-11&quot;:true,&quot;8-12&quot;:true,&quot;8-13&quot;:true,&quot;8-14&quot;:true,&quot;8-15&quot;:true,&quot;8-16&quot;:true,&quot;8-17&quot;:true,&quot;8-18&quot;:true,&quot;8-19&quot;:true,&quot;8-20&quot;:true,&quot;8-21&quot;:true,&quot;8-22&quot;:true,&quot;8-23&quot;:true,&quot;8-24&quot;:true,&quot;8-25&quot;:true,&quot;8-26&quot;:true,&quot;8-27&quot;:true,&quot;8-28&quot;:true,&quot;8-29&quot;:true,&quot;8-30&quot;:true,&quot;8-31&quot;:true,&quot;9-1&quot;:true,&quot;9-2&quot;:true,&quot;9-3&quot;:true,&quot;9-4&quot;:true,&quot;9-5&quot;:true,&quot;9-6&quot;:true,&quot;9-7&quot;:true,&quot;9-8&quot;:true,&quot;9-9&quot;:true,&quot;9-10&quot;:true,&quot;9-11&quot;:true,&quot;9-12&quot;:true,&quot;9-13&quot;:true,&quot;9-14&quot;:true,&quot;9-15&quot;:true,&quot;9-16&quot;:true,&quot;9-17&quot;:true,&quot;9-18&quot;:true,&quot;9-19&quot;:true,&quot;9-20&quot;:true,&quot;9-21&quot;:true,&quot;9-22&quot;:true,&quot;9-23&quot;:true,&quot;9-24&quot;:true,&quot;9-25&quot;:true,&quot;9-26&quot;:true,&quot;9-27&quot;:true,&quot;9-28&quot;:true,&quot;9-29&quot;:true,&quot;9-30&quot;:true,&quot;10-1&quot;:true,&quot;10-2&quot;:true,&quot;10-3&quot;:true,&quot;10-4&quot;:true,&quot;10-5&quot;:true,&quot;10-6&quot;:true,&quot;10-7&quot;:true,&quot;10-8&quot;:true,&quot;10-9&quot;:true,&quot;10-10&quot;:true,&quot;10-11&quot;:true,&quot;10-12&quot;:true,&quot;10-13&quot;:true,&quot;10-14&quot;:true,&quot;10-15&quot;:true,&quot;10-16&quot;:true,&quot;10-17&quot;:true,&quot;10-18&quot;:true,&quot;10-19&quot;:true,&quot;10-20&quot;:true,&quot;10-21&quot;:true,&quot;10-22&quot;:true,&quot;10-23&quot;:true,&quot;10-24&quot;:true,&quot;10-25&quot;:true,&quot;10-26&quot;:true,&quot;10-27&quot;:true,&quot;10-28&quot;:true,&quot;10-29&quot;:true,&quot;10-30&quot;:true,&quot;10-31&quot;:true,&quot;11-1&quot;:true,&quot;11-2&quot;:true,&quot;11-3&quot;:true,&quot;11-4&quot;:true,&quot;11-5&quot;:true,&quot;11-6&quot;:true,&quot;11-7&quot;:true,&quot;11-8&quot;:true,&quot;11-9&quot;:true,&quot;11-10&quot;:true,&quot;11-11&quot;:true,&quot;11-12&quot;:true,&quot;11-13&quot;:true,&quot;11-14&quot;:true,&quot;11-15&quot;:true,&quot;11-16&quot;:true,&quot;11-17&quot;:true,&quot;11-18&quot;:true,&quot;11-19&quot;:true,&quot;11-20&quot;:true,&quot;11-21&quot;:true,&quot;11-22&quot;:true,&quot;11-23&quot;:true,&quot;11-24&quot;:true,&quot;11-25&quot;:true,&quot;11-26&quot;:true,&quot;11-27&quot;:true,&quot;11-28&quot;:true,&quot;11-29&quot;:true,&quot;11-30&quot;:true,&quot;12-1&quot;:true,&quot;12-2&quot;:true,&quot;12-3&quot;:true,&quot;12-4&quot;:true,&quot;12-5&quot;:true,&quot;12-6&quot;:true,&quot;12-7&quot;:true,&quot;12-8&quot;:true,&quot;12-9&quot;:true,&quot;12-10&quot;:true,&quot;12-11&quot;:true,&quot;12-12&quot;:true,&quot;12-13&quot;:true,&quot;12-14&quot;:true,&quot;12-15&quot;:true,&quot;12-16&quot;:true,&quot;12-17&quot;:true,&quot;12-18&quot;:true,&quot;12-19&quot;:true,&quot;12-20&quot;:true,&quot;12-21&quot;:true,&quot;12-22&quot;:true,&quot;12-23&quot;:true,&quot;12-24&quot;:true,&quot;12-25&quot;:true,&quot;12-26&quot;:true,&quot;12-27&quot;:true,&quot;12-28&quot;:true,&quot;12-29&quot;:true,&quot;12-30&quot;:true,&quot;12-31&quot;:true},&quot;time_slots&quot;:[&quot;10:00&quot;,&quot;13:00&quot;],&quot;specs&quot;:[{&quot;name&quot;:&quot;Adults (Ages 13+)&quot;,&quot;values&quot;:[&quot;1 Adult&quot;,&quot;2 Adults&quot;,&quot;3 Adults&quot;,&quot;4 Adults&quot;,&quot;5 Adults&quot;]},{&quot;name&quot;:&quot;Children (Ages 4-12)&quot;,&quot;values&quot;:[&quot;0 Child&quot;,&quot;1 Child&quot;,&quot;2 Children&quot;,&quot;3 Children&quot;]}],&quot;skus&quot;:[{&quot;name&quot;:&quot;1 Adult \\\/ 0 Child&quot;,&quot;price&quot;:207,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-001&quot;},{&quot;name&quot;:&quot;1 Adult \\\/ 1 Child&quot;,&quot;price&quot;:254,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-002&quot;},{&quot;name&quot;:&quot;1 Adult \\\/ 2 Children&quot;,&quot;price&quot;:309,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-003&quot;},{&quot;name&quot;:&quot;1 Adult \\\/ 3 Children&quot;,&quot;price&quot;:380,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-004&quot;},{&quot;name&quot;:&quot;2 Adults \\\/ 0 Child&quot;,&quot;price&quot;:254,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-005&quot;},{&quot;name&quot;:&quot;2 Adults \\\/ 1 Child&quot;,&quot;price&quot;:309,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-006&quot;},{&quot;name&quot;:&quot;2 Adults \\\/ 2 Children&quot;,&quot;price&quot;:380,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-007&quot;},{&quot;name&quot;:&quot;2 Adults \\\/ 3 Children&quot;,&quot;price&quot;:475,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-008&quot;},{&quot;name&quot;:&quot;3 Adults \\\/ 0 Child&quot;,&quot;price&quot;:309,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-009&quot;},{&quot;name&quot;:&quot;3 Adults \\\/ 1 Child&quot;,&quot;price&quot;:380,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-010&quot;},{&quot;name&quot;:&quot;3 Adults \\\/ 2 Children&quot;,&quot;price&quot;:475,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-011&quot;},{&quot;name&quot;:&quot;3 Adults \\\/ 3 Children&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-012&quot;},{&quot;name&quot;:&quot;4 Adults \\\/ 0 Child&quot;,&quot;price&quot;:380,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-013&quot;},{&quot;name&quot;:&quot;4 Adults \\\/ 1 Child&quot;,&quot;price&quot;:475,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-014&quot;},{&quot;name&quot;:&quot;4 Adults \\\/ 2 Children&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-015&quot;},{&quot;name&quot;:&quot;4 Adults \\\/ 3 Children&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-016&quot;},{&quot;name&quot;:&quot;5 Adults \\\/ 0 Child&quot;,&quot;price&quot;:475,&quot;stock&quot;:1,&quot;code&quot;:&quot;91431-017&quot;},{&quot;name&quot;:&quot;5 Adults \\\/ 1 Child&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-018&quot;},{&quot;name&quot;:&quot;5 Adults \\\/ 2 Children&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-019&quot;},{&quot;name&quot;:&quot;5 Adults \\\/ 3 Children&quot;,&quot;price&quot;:0,&quot;stock&quot;:0,&quot;code&quot;:&quot;91431-020&quot;}],&quot;other_info&quot;:{&quot;address&quot;:&quot;Shanghai&quot;,&quot;p_price&quot;:&quot;95&quot;,&quot;p_tips&quot;:&quot;Indoor&quot;,&quot;duration&quot;:&quot;2 Hours&quot;,&quot;description_short&quot;:&quot;Create your own masterpiece in a guided Chinese painting session.&quot;,&quot;tripadvisor_url&quot;:&quot;https:\\\/\\\/www.tripadvisor.com\\\/AttractionProductReview-g308272-d33370371-Shanghai_Traditional_Chinese_Painting_experience_Workshop-Shanghai.html&quot;}}\"><\/li><li class=\"glopen-booking-section\"><p class=\"glopen-booking-stitle\">Desired Date<\/p><div class=\"glopen-booking-calendar\"><div class=\"glopen-calendar-header\"><button type=\"button\" class=\"glopen-calendar-prev\">&lt;<\/button><p id=\"current-month\">2026 Apr<\/p><button type=\"button\" class=\"glopen-calendar-next\">&gt;<\/button><\/div><div class=\"glopen-calendar-grid\"><div class=\"glopen-calendar-weekdays\"><div>Sun<\/div><div>Mon<\/div><div>Tue<\/div><div>Wed<\/div><div>Thu<\/div><div>Fri<\/div><div>Sat<\/div><\/div><div class=\"glopen-calendar-days\" id=\"calendar-days\"><\/div><\/div><\/div><\/li><li class=\"glopen-booking-section\"><p class=\"glopen-booking-stitle\">Desired Start Time<\/p><div class=\"glopen-booking-time-options\"><label class=\"glopen-booking-time-option\"><input type=\"radio\" name=\"selected_time\" value=\"10:00\" checked><span>10:00<\/span><\/label><label class=\"glopen-booking-time-option\"><input type=\"radio\" name=\"selected_time\" value=\"13:00\" ><span>13:00<\/span><\/label><\/div><\/li><\/ul><div class=\"glopen-booking-button-container\"><button type=\"button\" id=\"glopen-book-now-btn\" class=\"glopen-book-now-btn\">Book Now<\/button><\/div><\/form><div id=\"glopen-booking-modal\" class=\"glopen-booking-modal\"><div class=\"glopen-booking-modal-content\"><div class=\"glopen-booking-modal-left\"><div id=\"selected-summary\"><p id=\"selected-title\">4-Hour Chinese Painting Workshop in Shanghai<\/p><p><i>\uf073<\/i> <span id=\"selected-date\"><\/span> <span id=\"selected-time\"><\/span><\/p><p><i>\uf017<\/i> <span id=\"duration\"><\/span><\/p><p><i>\uf007<\/i> <span id=\"selected-sku-name\"><\/span><\/p><p id=\"total\">Total <span id=\"summary-price\"><\/span><\/p><\/div><\/div><div class=\"glopen-booking-modal-right\"><p class=\"glopen-booking-modal-title\">Confirm your booking<\/p><div class=\"glopen-customer-notice\"><i>r<\/i><div><p>Booking will only be confirmed after checkout<\/p><p>You will receive an email confirmation and detailed calendar invite after checking out.<\/p><\/div><\/div><form id=\"glopen-customer-info-form\"><div class=\"glopen-form-group\"><label for=\"customer-name\">Name*<\/label><input type=\"text\" id=\"customer-name\" name=\"customer_name\" placeholder=\"Enter your name\" required><\/div><div class=\"glopen-form-group\"><label for=\"customer-email\">Email*<\/label><input type=\"email\" id=\"customer-email\" name=\"customer_email\" placeholder=\"Enter your email\" required><\/div><div class=\"glopen-form-group\"><label for=\"customer-phone\">Phone Number*<\/label><input type=\"tel\" id=\"customer-phone\" name=\"customer_phone\" placeholder=\"Enter a phone number\" required><\/div><div class=\"glopen-form-group\"><label for=\"customer-notes\">Do you have any special notes we need to know about?<\/label><textarea id=\"customer-notes\" name=\"customer_notes\" rows=\"2\"><\/textarea><\/div><div class=\"glopen-form-group\"><p id=\"glopen-notic-one\">By signing up for this tour, you confirm that you agree to our *<\/p><label class=\"glopen-terms-label\"><input type=\"checkbox\" id=\"accept-terms\" name=\"accept_terms\" checked required><span>Terms of Service<\/span><\/label><ul id=\"glopen-notic-two\"><li><p>Cancellation policy:<\/p><ul><li>100% refund for cancellations made at least 24 hours before the tour start time.<\/li><li>No refund for cancellations made less than 24 hours before the tour or for no-shows.<\/li><li><strong>PayPal transactions:<\/strong> A 4.4% transaction fee applies to PayPal or PayPal-linked credit card payments. This fee is non-refundable since it cannot be reclaimed from PayPal or the credit card service in the event of a cancellation. For example, if you pay $100 via PayPal and cancel more than 24 hours in advance, you will receive $95.60.<\/li><\/ul><\/li><li><p>You are responsible for the safety of all participants in your group and travel insurance during the tour.<\/p><\/li><li><p>You consent to the use of my personal information for booking purposes.<\/p><\/li><li><p><strong>Privacy Policy:<\/strong> You acknowledge that your data will be stored securely and handled according to our privacy practices.<\/p><\/li><\/ul><\/div><div class=\"glopen-form-actions\"><button type=\"submit\" id=\"glopen-confirm-booking-btn\" class=\"glopen-confirm-booking-btn\">Confirm Booking<\/button><\/div><\/form><\/div><\/div><\/div><script type=\"text\/javascript\">document.addEventListener(\"DOMContentLoaded\", function() {\n            \/\/ \u83b7\u53d6\u5143\u7d20\n            const bookNowBtn = document.getElementById(\"glopen-book-now-btn\");\n            const modal = document.getElementById(\"glopen-booking-modal\");\n            const closeBtns = document.querySelectorAll(\".glopen-booking-modal-close, .glopen-booking-modal-close-btn\");\n            const selectedPriceEl = document.getElementById(\"selected-price\");\n            const summaryPriceEl = document.getElementById(\"summary-price\");\n            const selectedSkuNameEl = document.getElementById(\"selected-sku-name\");\n            const timeOptions = document.querySelectorAll(\"input[name='selected_time']\");\n            const selectedTimeEl = document.getElementById(\"selected-time\");\n            const customerInfoForm = document.getElementById(\"glopen-customer-info-form\");\n            const customerPhoneInput = document.getElementById(\"customer-phone\");\n            const specRadios = document.querySelectorAll(\"input[name^='spec_']\");\n            const mainContent = document.getElementById(\"main-content\");\n\n            \/\/ matchedSku\u53d8\u91cf\n            let matchedSku = null;\n            \n            \/\/ \u9500\u552e\u5c5e\u6027\u6570\u636e\n            const salesAttributesJson = document.getElementById(\"sales-attributes-json\");\n            const salesAttributes = salesAttributesJson ? JSON.parse(salesAttributesJson.value) : {};\n            \n            \/\/ \u521d\u59cb\u5316\u4ef7\u683c\n            \/\/ updateSelectedSkuAndPrice();\n\n            \/\/ \u521d\u59cb\u5316\u9009\u62e9\u7684\u89c4\u683c\u6837\u5f0f\n            \/\/ initSelectedSpecStyles();\n            \/\/ \u521d\u59cb\u5316\u65f6\u95f4\u9009\u9879\u6837\u5f0f\n            initSelectedTimeStyles();\n            \n            \/\/ \u521d\u59cb\u5316\u65e5\u5386\n            initCalendar();\n\n            \/\/ \u5728\u9875\u9762\u52a0\u8f7d\u5b8c\u6210\u540e\uff0c\u52a8\u6001\u9009\u62e9\u9ed8\u8ba4\u9009\u9879\n            selectDefaultSkuCombination();\n            \n            \/\/ \u89c4\u683c\u9009\u62e9\u4e8b\u4ef6 - \u66f4\u65b0\u4ef7\u683c\u548c\u53ef\u7528\u9009\u9879\n            specRadios.forEach(radio => {\n                radio.addEventListener(\"change\", function() {\n                    \/\/ \u83b7\u53d6\u5f53\u524dradio\u6240\u5728\u7684name\u7ec4\n                    const radioName = this.name;\n                    \n                    \/\/ \u79fb\u9664\u540c\u7ec4\u4e2d\u5176\u4ed6radio\u7684\u9009\u4e2d\u6837\u5f0f\n                    document.querySelectorAll(`input[name=\"${radioName}\"]`).forEach(input => {\n                        if (input !== this && input.closest('.glopen-spec-option')) {\n                            input.closest('.glopen-spec-option').classList.remove('glopen-spec-option-selected');\n                        }\n                    });\n                    \n                    \/\/ \u4e3a\u5f53\u524d\u9009\u4e2d\u7684radio\u7684label\u6dfb\u52a0\u9009\u4e2d\u6837\u5f0f\n                    if (this.checked && this.closest('.glopen-spec-option')) {\n                        this.closest('.glopen-spec-option').classList.add('glopen-spec-option-selected');\n                    }\n                    \n                    \/\/ \u66f4\u65b0\u5176\u4ed6\u89c4\u683c\u7ec4\u7684\u53ef\u7528\u9009\u9879\n                    updateAvailableOptions();\n                    \n                    \/\/ \u66f4\u65b0\u4ef7\u683c\u548cSKU\u4fe1\u606f\n                    updateSelectedSkuAndPrice();\n                });\n            });\n\n            \/\/ \u52a8\u6001\u9009\u62e9\u9ed8\u8ba4\u7684SKU\u7ec4\u5408\n            function selectDefaultSkuCombination() {\n                \/\/ \u5982\u679c\u6ca1\u6709SKU\u6216\u89c4\u683c\uff0c\u76f4\u63a5\u8fd4\u56de\n                if (!salesAttributes.skus || !salesAttributes.skus.length || \n                    !salesAttributes.specs || !salesAttributes.specs.length) {\n                    return;\n                }\n                \n                \/\/ \u83b7\u53d6\u6240\u6709\u89c4\u683c\u7ec4\u540d\u79f0\n                const specGroups = [];\n                specRadios.forEach(radio => {\n                    const radioName = radio.name;\n                    if (!specGroups.includes(radioName)) {\n                        specGroups.push(radioName);\n                    }\n                });\n                \n                \/\/ \u6e05\u9664\u6240\u6709\u5df2\u9009\u4e2d\u7684\u72b6\u6001\n                specRadios.forEach(radio => {\n                    radio.checked = false;\n                    if (radio.closest('.glopen-spec-option')) {\n                        radio.closest('.glopen-spec-option').classList.remove('glopen-spec-option-selected');\n                    }\n                });\n                \n                \/\/ \u5148\u542f\u7528\u6240\u6709\u9009\u9879\uff0c\u7136\u540e\u518d\u9009\u62e9\u9ed8\u8ba4\u9009\u9879\n                specRadios.forEach(radio => {\n                    enableRadio(radio);\n                });\n                \n                \/\/ \u904d\u5386\u6240\u6709\u89c4\u683c\u7ec4\uff0c\u4e3a\u6bcf\u4e2a\u7ec4\u9009\u62e9\u7b2c\u4e00\u4e2a\u53ef\u7528\u9009\u9879\n                specGroups.forEach(specGroupName => {\n                    \/\/ \u83b7\u53d6\u5f53\u524d\u89c4\u683c\u7ec4\u7684\u6240\u6709\u9009\u9879\n                    const currentGroupRadios = document.querySelectorAll(`input[name=\"${specGroupName}\"]`);\n                    \n                    \/\/ \u904d\u5386\u5f53\u524d\u7ec4\u7684\u9009\u9879\uff0c\u627e\u5230\u7b2c\u4e00\u4e2a\u6709\u5e93\u5b58\u7684\u9009\u9879\n                    for (let i = 0; i < currentGroupRadios.length; i++) {\n                        const radio = currentGroupRadios[i];\n                        const specValue = radio.value;\n                        let hasStock = false;\n                        \n                        \/\/ \u68c0\u67e5\u662f\u5426\u6709\u5305\u542b\u8be5\u89c4\u683c\u503c\u4e14\u6709\u5e93\u5b58\u7684SKU\n                        for (let j = 0; j < salesAttributes.skus.length; j++) {\n                            const sku = salesAttributes.skus[j];\n                            if (sku.stock > 0 && sku.name.includes(specValue)) {\n                                hasStock = true;\n                                break;\n                            }\n                        }\n                        \n                        \/\/ \u5982\u679c\u6709\u5e93\u5b58\u4e14\u5c1a\u672a\u9009\u4e2d\u4efb\u4f55\u9009\u9879\uff0c\u5219\u9009\u4e2d\u5b83\n                        if (hasStock && !document.querySelector(`input[name=\"${specGroupName}\"]:checked`)) {\n                            radio.checked = true;\n                            if (radio.closest('.glopen-spec-option')) {\n                                radio.closest('.glopen-spec-option').classList.add('glopen-spec-option-selected');\n                            }\n                            break; \/\/ \u627e\u5230\u7b2c\u4e00\u4e2a\u53ef\u7528\u9009\u9879\u540e\u8df3\u51fa\u5faa\u73af\n                        }\n                    }\n                });\n                \n                \/\/ \u66f4\u65b0\u53ef\u7528\u9009\u9879\u548c\u4ef7\u683c\n                updateAvailableOptions();\n                updateSelectedSkuAndPrice();\n                \n                \/\/ \u521d\u59cb\u5316\u9009\u4e2d\u7684\u89c4\u683c\u6837\u5f0f\n                initSelectedSpecStyles();\n            }\n            \n            \/\/ \u6839\u636e\u5f53\u524d\u5df2\u9009\u89c4\u683c\uff0c\u52a8\u6001\u66f4\u65b0\u5176\u4ed6\u89c4\u683c\u7ec4\u7684\u53ef\u7528\u9009\u9879\n            function updateAvailableOptions() {\n                \/\/ \u83b7\u53d6\u5f53\u524d\u5df2\u9009\u4e2d\u7684\u89c4\u683c\u503c\n                const selectedSpecValues = [];\n                specRadios.forEach(radio => {\n                    if (radio.checked && !radio.disabled) {\n                        selectedSpecValues.push(radio.value);\n                    }\n                });\n                \n                \/\/ \u83b7\u53d6\u6240\u6709\u89c4\u683c\u7ec4\u540d\u79f0\n                const specGroups = [];\n                const specGroupsObj = {};\n                specRadios.forEach(radio => {\n                    const radioName = radio.name;\n                    if (!specGroups.includes(radioName)) {\n                        specGroups.push(radioName);\n                        specGroupsObj[radioName] = [];\n                    }\n                    specGroupsObj[radioName].push(radio);\n                });\n                \n                \/\/ \u904d\u5386\u6bcf\u4e2a\u89c4\u683c\u7ec4\n                specGroups.forEach(specGroupName => {\n                    \/\/ \u5bf9\u4e8e\u6bcf\u4e2a\u89c4\u683c\u503c\uff0c\u68c0\u67e5\u662f\u5426\u6709\u5339\u914d\u7684SKU\n                    specGroupsObj[specGroupName].forEach(radio => {\n                        const specValue = radio.value;\n                        \n                        \/\/ \u5982\u679c\u8be5\u89c4\u683c\u503c\u5df2\u7ecf\u88ab\u9009\u4e2d\uff0c\u4fdd\u6301\u53ef\u7528\n                        if (radio.checked) {\n                            enableRadio(radio);\n                            return;\n                        }\n                        \n                        \/\/ \u68c0\u67e5\u662f\u5426\u5b58\u5728\u5305\u542b\u5f53\u524d\u5df2\u9009\u503c\u548c\u8be5\u89c4\u683c\u503c\u7684SKU\n                        let isAvailable = false;\n                        \n                        \/\/ \u5982\u679c\u8fd8\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u89c4\u683c\uff0c\u90a3\u4e48\u6240\u6709\u6709\u5e93\u5b58\u7684SKU\u5bf9\u5e94\u7684\u9009\u9879\u90fd\u5e94\u8be5\u662f\u53ef\u7528\u7684\n                        if (selectedSpecValues.length === 0) {\n                            for (let i = 0; i < salesAttributes.skus.length; i++) {\n                                const sku = salesAttributes.skus[i];\n                                if (sku.stock > 0 && sku.name.includes(specValue)) {\n                                    isAvailable = true;\n                                    break;\n                                }\n                            }\n                        } else {\n                            \/\/ \u5f53\u5df2\u6709\u9009\u4e2d\u7684\u89c4\u683c\u65f6\uff0c\u68c0\u67e5\u662f\u5426\u6709\u5339\u914d\u7684SKU\u7ec4\u5408\n                            for (let i = 0; i < salesAttributes.skus.length; i++) {\n                                const sku = salesAttributes.skus[i];\n                                \n                                \/\/ \u68c0\u67e5\u5e93\u5b58\n                                if (!sku.stock || sku.stock <= 0) {\n                                    continue;\n                                }\n                                \n                                \/\/ \u68c0\u67e5\u662f\u5426\u5305\u542b\u5f53\u524d\u89c4\u683c\u503c\n                                if (!sku.name.includes(specValue)) {\n                                    continue;\n                                }\n                                \n                                \/\/ \u68c0\u67e5\u662f\u5426\u5305\u542b\u6240\u6709\u5df2\u9009\u4e2d\u7684\u5176\u4ed6\u89c4\u683c\u503c\n                                let allOtherSelectedValuesMatch = true;\n                                for (let j = 0; j < selectedSpecValues.length; j++) {\n                                    \/\/ \u8df3\u8fc7\u540c\u7ec4\u7684\u5df2\u9009\u4e2d\u503c\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\n                                    const selectedRadio = document.querySelector(`input[value=\"${selectedSpecValues[j]}\"]`);\n                                    if (selectedRadio && selectedRadio.name === radio.name) {\n                                        continue;\n                                    }\n                                    \n                                    if (!sku.name.includes(selectedSpecValues[j])) {\n                                        allOtherSelectedValuesMatch = false;\n                                        break;\n                                    }\n                                }\n                                \n                                if (allOtherSelectedValuesMatch) {\n                                    isAvailable = true;\n                                    break;\n                                }\n                            }\n                        }\n                        \n                        \/\/ \u6839\u636e\u53ef\u7528\u6027\u542f\u7528\u6216\u7981\u7528radio\n                        if (isAvailable) {\n                            enableRadio(radio);\n                        } else {\n                            disableRadio(radio);\n                        }\n                    });\n                });\n            }\n            \n            \/\/ \u8f85\u52a9\u51fd\u6570\uff1a\u542f\u7528radio\u9009\u9879\n            function enableRadio(radio) {\n                if (radio && !radio.disabled) {\n                    return; \/\/ \u5df2\u7ecf\u662f\u542f\u7528\u72b6\u6001\n                }\n                \n                radio.disabled = false;\n                const label = radio.closest('.glopen-spec-option');\n                if (label) {\n                    label.classList.remove('glopen-spec-option-unavailable');\n                    const span = label.querySelector('span');\n                    if (span) {\n                        span.textContent = radio.value;\n                    }\n                }\n            }\n            \n            \/\/ \u8f85\u52a9\u51fd\u6570\uff1a\u7981\u7528radio\u9009\u9879\n            function disableRadio(radio) {\n                if (radio && radio.disabled) {\n                    return; \/\/ \u5df2\u7ecf\u662f\u7981\u7528\u72b6\u6001\n                }\n                \n                \/\/ \u5982\u679c\u5f53\u524dradio\u662f\u9009\u4e2d\u72b6\u6001\uff0c\u9700\u8981\u6e05\u9664\u9009\u4e2d\n                if (radio.checked) {\n                    radio.checked = false;\n                    const label = radio.closest('.glopen-spec-option');\n                    if (label) {\n                        label.classList.remove('glopen-spec-option-selected');\n                    }\n                }\n                \n                radio.disabled = true;\n                const label = radio.closest('.glopen-spec-option');\n                if (label) {\n                    label.classList.add('glopen-spec-option-unavailable');\n                    const span = label.querySelector('span');\n                    if (span) {\n                        span.textContent = radio.value;\n                    }\n                }\n            }\n            \n            \/\/ \u66f4\u65b0\u9009\u4e2d\u7684SKU\u548c\u4ef7\u683c\n            function updateSelectedSkuAndPrice() {\n                \/\/ \u83b7\u53d6\u5f53\u524d\u9009\u4e2d\u7684\u6240\u6709\u89c4\u683c\u503c\n                const selectedSpecValues = [];\n                specRadios.forEach(radio => {\n                    if (radio.checked) {\n                        selectedSpecValues.push(radio.value);\n                    }\n                });\n                \n                \/\/ \u5728\u6240\u6709SKU\u4e2d\u67e5\u627e\u5339\u914d\u7684\u7ec4\u5408\n                for (let i = 0; i < salesAttributes.skus.length; i++) {\n                    const sku = salesAttributes.skus[i];\n                    let allValuesMatch = true;\n                    \n                    \/\/ \u68c0\u67e5SKU\u540d\u79f0\u662f\u5426\u5305\u542b\u6240\u6709\u9009\u4e2d\u7684\u89c4\u683c\u503c\n                    for (let j = 0; j < selectedSpecValues.length; j++) {\n                        if (!sku.name.includes(selectedSpecValues[j])) {\n                            allValuesMatch = false;\n                            break;\n                        }\n                    }\n                    \n                    if (allValuesMatch && \n                        (sku.stock > 0 || sku.stock === undefined)) {\n                        matchedSku = sku;\n                        break;\n                    }\n                }\n                \n                \/\/ \u66f4\u65b0\u4ef7\u683c\u548c\u9009\u4e2d\u7684SKU\u540d\u79f0\n                if (matchedSku) {\n                    const price = matchedSku.price || 0;\n                    selectedPriceEl.textContent = \"$\" + price.toFixed(2);\n                    summaryPriceEl.textContent = \"$\" + price.toFixed(2);\n                    selectedSkuNameEl.textContent = matchedSku.name || \"Default option\";\n                }\n            }\n\n            \/\/ \u9875\u9762\u52a0\u8f7d\u5b8c\u6210\u540e\uff0c\u521d\u59cb\u5316\u9009\u4e2d\u7684\u89c4\u683c\u6837\u5f0f\n            function initSelectedSpecStyles() {\n                specRadios.forEach(radio => {\n                    if (radio.checked && radio.closest('.glopen-spec-option')) {\n                        radio.closest('.glopen-spec-option').classList.add('glopen-spec-option-selected');\n                    }\n                });\n            }\n            \/\/ \u521d\u59cb\u5316\u9009\u4e2d\u7684\u65f6\u95f4\u9009\u9879\u6837\u5f0f\n            function initSelectedTimeStyles() {\n                timeOptions.forEach(option => {\n                    if (option.checked && option.closest('.glopen-booking-time-option')) {\n                        option.closest('.glopen-booking-time-option').classList.add('glopen-time-option-selected');\n                        selectedTimeEl.textContent = option.value;\n                    }\n                });\n            }\n            \n            \/\/ \u65f6\u95f4\u9009\u62e9\u4e8b\u4ef6\n            timeOptions.forEach(option => {\n                option.addEventListener(\"change\", function() {\n                    if (this.checked) {\n                        selectedTimeEl.textContent = this.value;\n                        \n                        \/\/ \u79fb\u9664\u6240\u6709\u65f6\u95f4\u9009\u9879\u7684\u9009\u4e2d\u6837\u5f0f\n                        timeOptions.forEach(opt => {\n                            if (opt.closest('.glopen-booking-time-option')) {\n                                opt.closest('.glopen-booking-time-option').classList.remove('glopen-time-option-selected');\n                            }\n                        });\n                        \n                        \/\/ \u4e3a\u5f53\u524d\u9009\u4e2d\u7684\u65f6\u95f4\u9009\u9879\u6dfb\u52a0\u9009\u4e2d\u6837\u5f0f\n                        if (this.closest('.glopen-booking-time-option')) {\n                            this.closest('.glopen-booking-time-option').classList.add('glopen-time-option-selected');\n                        }\n                    }\n                });\n            });\n            \n            \/\/ \u6253\u5f00\u5f39\u7a97\n            bookNowBtn.addEventListener(\"click\", function() {\n                \/\/ \u9a8c\u8bc1\u662f\u5426\u9009\u62e9\u4e86\u65e5\u671f\n                const selectedDate = document.getElementById(\"selected-date\").textContent;\n                if (selectedDate === \"Not selected\" || !selectedDate) {\n                    alert(\"Please select a date\");\n                    return;\n                }\n                \n                \/\/ \u9a8c\u8bc1\u662f\u5426\u9009\u62e9\u4e86\u9009\u9879\n                updateSelectedSkuAndPrice(); \/\/ \u786e\u4fddmatchedSku\u662f\u6700\u65b0\u7684\n                if (!matchedSku || matchedSku.stock <= 0) {\n                    alert(\"Please select a valid product option\");\n                    return;\n                }\n\n                \/\/ \u663e\u793a\u5730\u5740\u4fe1\u606f\n                const selectedCityEl = document.getElementById(\"address\");\n                if (selectedCityEl) {\n                    if (salesAttributes && salesAttributes.other_info.address) {\n                        selectedCityEl.textContent = salesAttributes.other_info.address;\n                    } else {\n                        selectedCityEl.textContent = \"Address not set\";\n                    }\n                }\n                \n\n                \/\/ \u663e\u793a\u65f6\u957f\u4fe1\u606f\n                const durationE2 = document.getElementById(\"duration\");\n                if (durationE2) {\n                    if (salesAttributes && salesAttributes.other_info.duration) {\n                        durationE2.textContent = salesAttributes.other_info.duration;\n                    } else {\n                        durationE2.textContent = \"Duration not set\";\n                    }\n                }\n                \n                \n                \/\/ \u9a8c\u8bc1\u662f\u5426\u9009\u62e9\u4e86\u65f6\u95f4\n                const selectedTime = document.querySelector(\"input[name='selected_time']:checked\");\n                if (!selectedTime) {\n                    alert(\"Please select a time\");\n                    return;\n                }\n                \n                \/\/ \u7981\u6b62body\u6eda\u52a8\n                document.body.style.overflow = \"hidden\";\n                \/\/ \u63d0\u9ad8main-content\u7684z-index\uff0c\u907f\u514d\u88abfooter\u906e\u6321\n                mainContent.style.zIndex = \"99999\";\n                mainContent.style.position = \"relative\";\n                \/\/ \u6240\u6709\u9a8c\u8bc1\u901a\u8fc7\uff0c\u6253\u5f00\u5f39\u7a97\n                modal.style.display = \"block\";\n            });\n            \n            \/\/ \u5173\u95ed\u5f39\u7a97\u4e8b\u4ef6\n            closeBtns.forEach(btn => {\n                btn.addEventListener(\"click\", function() {\n                    modal.style.display = \"none\";\n                    \/\/ \u6062\u590dbody\u6eda\u52a8\n                    document.body.style.overflow = \"\";\n                    \/\/ \u6062\u590dmain-content\u7684z-index\n                    mainContent.style.zIndex = \"\";\n                    mainContent.style.position = \"\";\n                });\n            });\n            \n            \/\/ \u70b9\u51fb\u5f39\u7a97\u5916\u90e8\u5173\u95ed\u5f39\u7a97\n            window.addEventListener(\"click\", function(event) {\n                if (event.target === modal) {\n                    modal.style.display = \"none\";\n                    \/\/ \u6062\u590dbody\u6eda\u52a8\n                    document.body.style.overflow = \"\";\n                    \/\/ \u6062\u590dmain-content\u7684z-index\n                    mainContent.style.zIndex = \"\";\n                    mainContent.style.position = \"\";\n                }\n            });\n            \n            \/\/ \u8868\u5355\u63d0\u4ea4\u4e8b\u4ef6\n            customerInfoForm.addEventListener(\"submit\", function(event) {\n                event.preventDefault();\n                \n                \/\/ \u7535\u8bdd\u8f93\u5165\n                const phoneInput = document.querySelector(\"input[type='tel']\");\n                if (!phoneInput.value) {\n                    alert(\"Please enter a valid phone number\");\n                    return;\n                }\n                \n                \/\/ \u91cd\u65b0\u83b7\u53d6\u5339\u914d\u7684SKU\n                updateSelectedSkuAndPrice();\n\n                const submitBtn = document.getElementById('glopen-confirm-booking-btn');\n                const originalText = submitBtn.innerHTML;\n                submitBtn.innerHTML = '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"animation:spin 1s linear infinite;vertical-align:middle\"><circle cx=\"12\" cy=\"12\" r=\"10\"><\/circle><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"><\/path><\/svg> Processing...';\n                submitBtn.disabled = true;\n                \n                \/\/ \u83b7\u53d6\u8868\u5355\u6570\u636e\n                const formData = new FormData();\n                const bookingData = {\n                    product_id: document.querySelector(\"input[name='product_id']\").value,\n                    selected_sku: matchedSku ? (matchedSku.id || salesAttributes.skus.indexOf(matchedSku)) : '',\n                    selected_date: convertDateFormat(document.getElementById(\"selected-date\").textContent),\n                    selected_time: document.querySelector(\"input[name='selected_time']:checked\").value,\n                    customer_name: document.querySelector(\"input[name='customer_name']\").value,\n                    customer_email: document.querySelector(\"input[name='customer_email']\").value,\n                    customer_phone: document.querySelector(\"input[name='customer_phone']\").value,\n                    customer_notes: document.querySelector(\"textarea[name='customer_notes']\").value || '',\n                };\n                formData.append('action', 'glopen_order_submits'); \/\/ \u7cfb\u7edf\u884c\u4e3a\n                formData.append('do', 'submit'); \/\/ \u81ea\u5b9a\u4e49\u884c\u4e3a\n                formData.append('csrf', 'f7b52c0795'); \/\/ CSRF \u4fdd\u62a4\n                formData.append('data', JSON.stringify(bookingData)); \/\/ \u8868\u5355\u6570\u636e\n                \n                fetch(\"https:\/\/gl-open.com\/wp-admin\/admin-ajax.php\", {\n                    method: 'POST',\n                    body: formData\n                })\n                .then(response => response.json())\n                .then(data => {\n                    \/\/ \u6062\u590d\u6309\u94ae\u72b6\u6001\n                    submitBtn.innerHTML = originalText;\n                    submitBtn.disabled = false;\n\n                    if (data.success) {\n                        alert(data.message.replace(\/\\\\n\/g, '\\n'));\n                        \/\/ \u6dfb\u52a0\u4ee5\u4e0b\u8df3\u8f6c\u4ee3\u7801\n                        if (data.order_url) {\n                            window.location.replace(data.order_url);\n                        }\n                    } else {\n                        alert(data.message);\n                    }\n                })\n                .catch(error => {\n                    \/\/ \u53d1\u751f\u9519\u8bef\u65f6\u4e5f\u6062\u590d\u6309\u94ae\u72b6\u6001\n                    submitBtn.innerHTML = originalText;\n                    submitBtn.disabled = false;\n                    console.error('\u63d0\u4ea4\u8ba2\u5355\u65f6\u51fa\u9519:', error);\n                    alert('An error occurred while submitting the order. Please try again.');\n                });\n            });\n\n            \/\/ \u65e5\u671f\u683c\u5f0f\u8f6c\u53d8\n            function convertDateFormat(dateString) {\n                \/\/ \u5b9a\u4e49\u6708\u4efd\u7f29\u5199\u5230\u6570\u5b57\u7684\u6620\u5c04\n                const monthMap = {\n                    'Jan': '01',\n                    'Feb': '02',\n                    'Mar': '03',\n                    'Apr': '04',\n                    'May': '05',\n                    'Jun': '06',\n                    'Jul': '07',\n                    'Aug': '08',\n                    'Sep': '09',\n                    'Oct': '10',\n                    'Nov': '11',\n                    'Dec': '12'\n                };\n                \n                \/\/ \u5206\u5272\u65e5\u671f\u5b57\u7b26\u4e32\n                \/\/ \u4f8b\u5982 \"Tuesday, Sep 30, 2025\" \u5206\u5272\u540e\u5f97\u5230 [\"Tuesday\", \"Sep\", \"30\", \"2025\"]\n                const parts = dateString.split(\/,?\\s+\/);\n                \n                \/\/ \u63d0\u53d6\u6708\u3001\u65e5\u3001\u5e74\n                const month = monthMap[parts[1]];\n                let day = parts[2];\n                const year = parts[3];\n                \n                \/\/ \u786e\u4fdd\u65e5\u671f\u662f\u4e24\u4f4d\u6570\uff08\u5982 5 \u8f6c\u4e3a 05\uff09\n                if (day.length === 1) {\n                    day = '0' + day;\n                }\n                \n                \/\/ \u7ec4\u5408\u6210 YYYY-MM-DD \u683c\u5f0f\n                return `${year}-${month}-${day}`;\n            }\n            \n            \/\/ \u521d\u59cb\u5316\u65e5\u5386\u51fd\u6570\n            function initCalendar() {\n                const calendarDays = document.getElementById(\"calendar-days\");\n                const currentMonthEl = document.getElementById(\"current-month\");\n                const prevMonthBtn = document.querySelector(\".glopen-calendar-prev\");\n                const nextMonthBtn = document.querySelector(\".glopen-calendar-next\");\n                \n                \/\/ \u68c0\u67e5\u65e5\u5386\u5143\u7d20\u662f\u5426\u5b58\u5728\n                if (!calendarDays || !currentMonthEl || !prevMonthBtn || !nextMonthBtn) {\n                    console.log(\"\u65e5\u5386\u5143\u7d20\u672a\u627e\u5230\uff0c\u8df3\u8fc7\u65e5\u5386\u521d\u59cb\u5316\");\n                    return;\n                }\n                \n                let currentDate = new Date();\n                let selectedDate = null;\n                \n                \/\/ \u6e32\u67d3\u65e5\u5386\n                function renderCalendar() {\n                    calendarDays.innerHTML = '';\n                    \n                    const year = currentDate.getFullYear();\n                    const month = currentDate.getMonth();\n                    const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n                    currentMonthEl.textContent = `${months[month]} ${year}`;\n                    \n                    \/\/ \u83b7\u53d6\u5f53\u6708\u7b2c\u4e00\u5929\n                    const firstDay = new Date(year, month, 1);\n                    \/\/ \u83b7\u53d6\u5f53\u6708\u6700\u540e\u4e00\u5929\n                    const lastDay = new Date(year, month + 1, 0);\n                    \n                    \/\/ \u83b7\u53d6\u5f53\u6708\u7b2c\u4e00\u5929\u662f\u661f\u671f\u51e0\n                    const firstDayIndex = firstDay.getDay();\n                    \/\/ \u83b7\u53d6\u5f53\u6708\u7684\u603b\u5929\u6570\n                    const daysInMonth = lastDay.getDate();\n                    \n                    \/\/ \u8ba1\u7b97\u5f53\u524d\u65e5\u671f\u5f80\u540e2\u5929\u7684\u65e5\u671f\u4f5c\u4e3a\u5206\u754c\u7ebf\n                    const today = new Date();\n                    const cutoffDate = new Date(today);\n                    cutoffDate.setDate(today.getDate() + 2); \/\/ \u5f80\u540e2\u5929\u7684\u65e5\u671f\n                    \n                    \/\/ \u68c0\u67e5\u662f\u5426\u662f\u672c\u6708\u6700\u540e2\u5929\uff0c\u5982\u679c\u662f\u4e14\u6240\u6709\u65e5\u671f\u90fd\u4e0d\u53ef\u9009\uff0c\u5219\u81ea\u52a8\u663e\u793a\u4e0b\u4e2a\u6708\n                    const isLastTwoDaysOfMonth = (today.getDate() >= daysInMonth - 1) && \n                                               (today.getMonth() === month) && \n                                               (today.getFullYear() === year);\n                    \n                    let shouldCheckForAutoNextMonth = isLastTwoDaysOfMonth;\n                    let hasAvailableDatesInCurrentMonth = false;\n                    \n                    let shouldSelectFirstAvailableDate = true; \/\/ \u6807\u8bb0\u662f\u5426\u9700\u8981\u9009\u62e9\u7b2c\u4e00\u4e2a\u53ef\u7528\u65e5\u671f\n                    let firstAvailableDateElement = null; \/\/ \u5b58\u50a8\u7b2c\u4e00\u4e2a\u53ef\u7528\u65e5\u671f\u7684\u5143\u7d20\n                    \n                    \/\/ \u6dfb\u52a0\u4e0a\u4e2a\u6708\u7684\u65e5\u671f\u5360\u4f4d\u7b26\n                    for (let i = 0; i < firstDayIndex; i++) {\n                        const emptyDay = document.createElement('div');\n                        emptyDay.classList.add('glopen-calendar-day', 'glopen-calendar-day-empty');\n                        calendarDays.appendChild(emptyDay);\n                    }\n                    \n                    \/\/ \u6dfb\u52a0\u5f53\u6708\u7684\u65e5\u671f\n                    for (let i = 1; i <= daysInMonth; i++) {\n                        const day = document.createElement('div');\n                        day.classList.add('glopen-calendar-day');\n                        day.textContent = i;\n                        \n                        \/\/ \u6784\u5efa\u5b8c\u6574\u65e5\u671f\u5b57\u7b26\u4e32\u7528\u4e8e\u6bd4\u8f83\n                        const fullDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}`;\n                        const currentDateObj = new Date(year, month, i);\n\n                        \/\/ \u68c0\u67e5\u662f\u5426\u662f\u5f53\u5929\u65e5\u671f\n                        const isToday = currentDateObj.getDate() === today.getDate() &&\n                                    currentDateObj.getMonth() === today.getMonth() &&\n                                    currentDateObj.getFullYear() === today.getFullYear();\n                        \n                        \/\/ \u5982\u679c\u662f\u5f53\u5929\u65e5\u671f\uff0c\u6dfb\u52a0\u7279\u6b8aclass\n                        if (isToday) {\n                            day.classList.add('glopen-calendar-today');\n                        }\n                        \n                        \/\/ \u68c0\u67e5\u662f\u5426\u662f\u4e0d\u53ef\u552e\u65e5\u671f\n                        let isUnavailable = false;\n                        if (salesAttributes && salesAttributes.selected_dates) {\n                            \/\/ \u6784\u5efa\u6708\u4efd-\u65e5\u671f\u683c\u5f0f\u7684\u952e\uff0c\u5982 \"9-1\" \u8868\u793a9\u67081\u65e5\n                            const monthDayKey = `${month + 1}-${i}`;\n                            \/\/ \u68c0\u67e5\u8be5\u65e5\u671f\u662f\u5426\u6807\u8bb0\u4e3a\u4e0d\u53ef\u552e\n                            isUnavailable = !salesAttributes.selected_dates[monthDayKey];\n                        }\n                        \n                        \/\/ \u68c0\u67e5\u662f\u5426\u5728\u5206\u754c\u7ebf\u4e4b\u524d\uff08\u5f53\u524d\u65f6\u95f4\u5f80\u540e2\u5929\u5185\uff09\n                        if (currentDateObj <= cutoffDate) {\n                            isUnavailable = true;\n                        }\n                        \n                        if (isUnavailable) {\n                            day.classList.add('glopen-calendar-day-unavailable');\n                            \/\/ \u786e\u4fdd\u4e0d\u53ef\u552e\u65e5\u671f\u4e0d\u80fd\u88ab\u9009\u4e2d\n                            day.style.pointerEvents = 'none';\n                        } else {\n                            hasAvailableDatesInCurrentMonth = true;\n                            \/\/ \u5982\u679c\u662f\u53ef\u552e\u65e5\u671f\u4e14\u5728\u5206\u754c\u7ebf\u4e4b\u540e\uff0c\u8bb0\u5f55\u7b2c\u4e00\u4e2a\u53ef\u7528\u65e5\u671f\n                            if (currentDateObj > cutoffDate && shouldSelectFirstAvailableDate) {\n                                firstAvailableDateElement = day;\n                                shouldSelectFirstAvailableDate = false;\n                            }\n                            \n                            \/\/ \u4ec5\u5bf9\u53ef\u552e\u65e5\u671f\u6dfb\u52a0\u70b9\u51fb\u4e8b\u4ef6\n                            day.addEventListener('click', function() {\n                                \/\/ \u79fb\u9664\u5176\u4ed6\u65e5\u671f\u7684\u9009\u4e2d\u72b6\u6001\n                                document.querySelectorAll('.glopen-calendar-day-selected').forEach(day => {\n                                    day.classList.remove('glopen-calendar-day-selected');\n                                });\n                                \n                                \/\/ \u6dfb\u52a0\u5f53\u524d\u65e5\u671f\u7684\u9009\u4e2d\u72b6\u6001\n                                this.classList.add('glopen-calendar-day-selected');\n                                \n                                \/\/ \u66f4\u65b0\u9009\u4e2d\u7684\u65e5\u671f\n                                selectedDate = fullDate;\n                                document.getElementById('selected-date').textContent = formatDateToEnglish(fullDate);\n                            });\n                        }\n                        \n                        calendarDays.appendChild(day);\n                    }\n\n                    \/\/ \u5982\u679c\u662f\u6708\u5e95\u6700\u540e2\u5929\u4e14\u5f53\u6708\u6ca1\u6709\u53ef\u7528\u65e5\u671f\uff0c\u81ea\u52a8\u663e\u793a\u4e0b\u4e2a\u6708\n                    if (shouldCheckForAutoNextMonth && !hasAvailableDatesInCurrentMonth) {\n                        const newDate = new Date(currentDate);\n                        newDate.setMonth(newDate.getMonth() + 1);\n                        \n                        \/\/ \u53ea\u5141\u8bb8\u5f80\u540e\u67e5\u770b3\u4e2a\u6708\n                        const today = new Date();\n                        const maxMonth = today.getMonth() + 3;\n                        const currentYear = today.getFullYear();\n                        const newTotalMonths = newDate.getFullYear() * 12 + newDate.getMonth();\n                        const maxTotalMonths = currentYear * 12 + maxMonth;\n                        \n                        \/\/ \u786e\u4fdd\u4e0d\u8d85\u8fc7\u6700\u5927\u5141\u8bb8\u6708\u4efd\n                        if (newTotalMonths <= maxTotalMonths) {\n                            currentDate = newDate;\n                            renderCalendar(); \/\/ \u91cd\u65b0\u6e32\u67d3\u65e5\u5386\u663e\u793a\u4e0b\u4e2a\u6708\n                            return; \/\/ \u7ec8\u6b62\u5f53\u524d\u51fd\u6570\u6267\u884c\n                        }\n                    }\n\n                    \/\/ \u5982\u679c\u627e\u5230\u4e86\u7b2c\u4e00\u4e2a\u53ef\u7528\u65e5\u671f\uff0c\u5c06\u5176\u8bbe\u7f6e\u4e3a\u9ed8\u8ba4\u9009\u4e2d\n                    if (firstAvailableDateElement) {\n                        firstAvailableDateElement.click(); \/\/ \u89e6\u53d1\u70b9\u51fb\u4e8b\u4ef6\u6765\u9009\u62e9\u8be5\u65e5\u671f\n                    }\n\n                    \/\/ \u6dfb\u52a0\u65e5\u671f\u683c\u5f0f\u5316\u51fd\u6570\n                    function formatDateToEnglish(dateString) {\n                        const options = {\n                            weekday: 'long',\n                            year: 'numeric',\n                            month: 'short',\n                            day: 'numeric'\n                        };\n                        const date = new Date(dateString);\n                        return date.toLocaleDateString('en-US', options);\n                    }\n\n                    updateMonthButtons();\n                }\n                \n                \/\/ \u4e0a\u4e2a\u6708\u6309\u94ae\u70b9\u51fb\u4e8b\u4ef6\n                prevMonthBtn.addEventListener('click', function() {\n                    \/\/ \u53ea\u5141\u8bb8\u56de\u5230\u5f53\u524d\u6708\u4efd\n                    const today = new Date();\n                    const currentMonth = today.getMonth();\n                    const currentYear = today.getFullYear();\n                    \n                    const newDate = new Date(currentDate);\n                    newDate.setMonth(newDate.getMonth() - 1);\n                    \n                    \/\/ \u4e0d\u5141\u8bb8\u56de\u5230\u5f53\u524d\u6708\u4efd\u4e4b\u524d\n                    if (newDate.getFullYear() < currentYear || \n                        (newDate.getFullYear() === currentYear && newDate.getMonth() < currentMonth)) {\n                        return;\n                    }\n                    \n                    currentDate = newDate;\n                    renderCalendar();\n                });\n                \n                \/\/ \u4e0b\u4e2a\u6708\u6309\u94ae\u70b9\u51fb\u4e8b\u4ef6\n                nextMonthBtn.addEventListener('click', function() {\n                    \/\/ \u53ea\u5141\u8bb8\u5f80\u540e\u67e5\u770b3\u4e2a\u6708\n                    const today = new Date();\n                    const maxMonth = today.getMonth() + 3;\n                    const currentYear = today.getFullYear();\n                    \n                    const newDate = new Date(currentDate);\n                    newDate.setMonth(newDate.getMonth() + 1);\n                    \n                    \/\/ \u8ba1\u7b97\u65b0\u65e5\u671f\u7684\u603b\u6708\u6570\uff08\u7528\u4e8e\u6bd4\u8f83\u662f\u5426\u8d85\u8fc7\u9650\u5236\uff09\n                    const newTotalMonths = newDate.getFullYear() * 12 + newDate.getMonth();\n                    const maxTotalMonths = currentYear * 12 + maxMonth;\n                    \n                    \/\/ \u4e0d\u5141\u8bb8\u8d85\u8fc7\u5f53\u524d\u6708\u4efd+3\u4e2a\u6708\u7684\u8303\u56f4\n                    if (newTotalMonths > maxTotalMonths) {\n                        return;\n                    }\n                    \n                    currentDate = newDate;\n                    renderCalendar();\n                });\n                \n                \/\/ \u66f4\u65b0\u6708\u4efd\u6309\u94ae\u72b6\u6001\n                function updateMonthButtons() {\n                    const today = new Date();\n                    const currentMonth = today.getMonth();\n                    const currentYear = today.getFullYear();\n                    const maxMonth = today.getMonth() + 3;\n                    const maxTotalMonths = currentYear * 12 + maxMonth;\n                    const currentTotalMonths = currentDate.getFullYear() * 12 + currentDate.getMonth();\n                    \n                    \/\/ \u5982\u679c\u662f\u5f53\u524d\u6708\u4efd\uff0c\u7981\u7528\u4e0a\u4e2a\u6708\u6309\u94ae\n                    if (currentDate.getFullYear() === currentYear && currentDate.getMonth() === currentMonth) {\n                        prevMonthBtn.disabled = true;\n                        prevMonthBtn.classList.add('disabled');\n                    } else {\n                        prevMonthBtn.disabled = false;\n                        prevMonthBtn.classList.remove('disabled');\n                    }\n                    \n                    \/\/ \u5982\u679c\u662f\u6700\u5927\u5141\u8bb8\u6708\u4efd\uff0c\u7981\u7528\u4e0b\u4e2a\u6708\u6309\u94ae\n                    if (currentTotalMonths >= maxTotalMonths) {\n                        nextMonthBtn.disabled = true;\n                        nextMonthBtn.classList.add('disabled');\n                    } else {\n                        nextMonthBtn.disabled = false;\n                        nextMonthBtn.classList.remove('disabled');\n                    }\n                }\n                \n                \/\/ \u521d\u59cb\u6e32\u67d3\n                renderCalendar();\n            }\n        });<\/script>[\/et_pb_code][et_pb_blurb title=&#8221;Have booking questions?&#8221; use_icon=&#8221;on&#8221; font_icon=&#8221;&#xf879;||fa||900&#8243; icon_color=&#8221;#000000&#8243; icon_placement=&#8221;left&#8221; image_icon_width=&#8221;1.25em&#8221; _builder_version=&#8221;4.27.4&#8243; _module_preset=&#8221;default&#8221; header_font=&#8221;|600|||||||&#8221; header_text_color=&#8221;#000000&#8243; body_font=&#8221;|600|||||||&#8221; body_text_color=&#8221;#000000&#8243; body_font_size=&#8221;1.25rem&#8221; background_color=&#8221;#dbd2c3&#8243; image_icon_custom_margin=&#8221;||||false|false&#8221; custom_margin=&#8221;1.5rem||||false|false&#8221; custom_padding=&#8221;1.5rem|1.5rem|1.5rem|1.5rem|true|true&#8221; link_option_url=&#8221;tel:+862164181086&#8243; custom_css_free_form=&#8221;selector h4 {||  font-size: 1rem !important;||  padding-bottom: 0||}||selector .et_pb_main_blurb_image {||  padding-top: .5rem;||}&#8221; border_radii=&#8221;on|0.5rem|0.5rem|0.5rem|0.5rem&#8221; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p>+86 2164181086<\/p>\n<p>[\/et_pb_blurb][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Experience traditional Chinese painting in Shanghai with a hands-on workshop. Unlike Western painting, Chinese art blends philosophy, symbolism, and technique into every brushstroke. Learn the history, philosophy, and symbolism behind this ancient art, then watch a live demonstration and try the techniques yourself. Guided by an expert, you\u2019ll create your own meaningful artwork to take [&hellip;]<\/p>\n","protected":false},"featured_media":92498,"template":"","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"1080"},"glopen_product_category":[69],"class_list":["post-92501","glopen_product","type-glopen_product","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/glopen_product\/92501","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/glopen_product"}],"about":[{"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/types\/glopen_product"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/media\/92498"}],"wp:attachment":[{"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/media?parent=92501"}],"wp:term":[{"taxonomy":"glopen_product_category","embeddable":true,"href":"https:\/\/gl-open.com\/wp-json\/wp\/v2\/glopen_product_category?post=92501"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}