{"id":10109,"date":"2025-08-20T14:15:49","date_gmt":"2025-08-20T14:15:49","guid":{"rendered":"https:\/\/lumalofts.ca\/?page_id=10109"},"modified":"2026-02-24T15:32:35","modified_gmt":"2026-02-24T15:32:35","slug":"event-venues-workshops","status":"publish","type":"page","link":"https:\/\/lumalofts.ca\/fr\/weddings\/event-venues-workshops\/","title":{"rendered":"Event Venues &amp; Workshops"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"10109\" class=\"elementor elementor-10109\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6a3d361 e-con-full e-flex e-con e-parent\" data-id=\"6a3d361\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t<div class=\"elementor-element elementor-element-2ff0f44 e-con-full e-flex e-con e-child\" data-id=\"2ff0f44\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div data-animation-type=\"block\" class=\"elementor-element elementor-element-cf30751 animated-slow elementor-widget__width-initial mauve-separator-align-center elementor-widget elementor-widget-mauve-fancy_heading\" data-id=\"cf30751\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;none&quot;,&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"mauve-fancy_heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"mauve-fancy-heading mauve-heading-text-center\">\n\t\t\t<div class=\"mauve-fancy-heading-inner\">\n\t\t\t\t<h1 class=\"mauve-heading-subtitle\">Montreal Event space<\/h1><h2 class=\"mauve-heading-title\">A Space That Shapes Itself Around Your Gathering<\/h2><div class=\"mauve-heading-content entry-content\"><p>Luma Lofts is a natural-light event space in Montreal perfect for intimate gatherings, workshops, and small celebrations. It accommodates up to 35 guests and includes tables, chairs, and setup. Ideal for baby showers, bridal showers, networking events and workshops.<\/p>\n<\/div>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6c97a11 e-con-full e-flex e-con e-child\" data-id=\"6c97a11\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;slideshow&quot;,&quot;background_slideshow_gallery&quot;:[{&quot;id&quot;:10117,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-2548_websize.jpg&quot;},{&quot;id&quot;:9984,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-2798_websize.jpg&quot;},{&quot;id&quot;:10118,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-2538_websize.jpg&quot;},{&quot;id&quot;:10116,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-2487_websize.jpg&quot;}],&quot;background_slideshow_slide_duration&quot;:2000,&quot;background_slideshow_loop&quot;:&quot;yes&quot;,&quot;background_slideshow_slide_transition&quot;:&quot;fade&quot;,&quot;background_slideshow_transition_duration&quot;:500,&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7a48058 e-flex e-con-boxed e-con e-parent\" data-id=\"7a48058\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-cbfb2c4 e-con-full e-flex e-con e-child\" data-id=\"cbfb2c4\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-eea7471 e-flex e-con-boxed e-con e-parent\" data-id=\"eea7471\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-28254ab e-con-full e-flex e-con e-child\" data-id=\"28254ab\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;slideshow&quot;,&quot;background_slideshow_gallery&quot;:[{&quot;id&quot;:9992,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/PAM_8182_websize.jpg&quot;},{&quot;id&quot;:10023,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-2469_websize.jpg&quot;},{&quot;id&quot;:9981,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/Pam-Kay-Montreal-Dubai-Photographer-3440_websize.jpg&quot;},{&quot;id&quot;:10003,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/ElegantWedding-1253.jpg&quot;},{&quot;id&quot;:9954,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/IMG_7019-scaled.jpg&quot;},{&quot;id&quot;:9956,&quot;url&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/IMG_7015-scaled.jpg&quot;}],&quot;background_slideshow_slide_duration&quot;:3001,&quot;background_slideshow_loop&quot;:&quot;yes&quot;,&quot;background_slideshow_slide_transition&quot;:&quot;fade&quot;,&quot;background_slideshow_transition_duration&quot;:500,&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-21b7aa8 e-con-full e-flex e-con e-child\" data-id=\"21b7aa8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div data-animation-type=\"block\" class=\"elementor-element elementor-element-2952660 animated-slow mauve-separator-align-left animation_type_block elementor-invisible elementor-widget elementor-widget-mauve-fancy_heading\" data-id=\"2952660\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeIn&quot;,&quot;mauve_hidepaged&quot;:&quot;false&quot;,&quot;_animation_type&quot;:&quot;block&quot;}\" data-widget_type=\"mauve-fancy_heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"mauve-fancy-heading mauve-heading-text-left\">\n\t\t\t<div class=\"mauve-fancy-heading-inner\">\n\t\t\t\t<h2 class=\"mauve-heading-title\">Not to be dramatic, but this is why we\u2019re perfect:<\/h2>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-742a850 elementor-view-framed elementor-shape-square elementor-position-inline-start elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box\" data-id=\"742a850\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\t\t\t<div class=\"elementor-icon-box-icon\">\n\t\t\t\t<span  class=\"elementor-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"ms-icons ms-check\"><\/i>\t\t\t\t<\/span>\n\t\t\t<\/div>\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tParking options that don\u2019t make you cry\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tStreet parking is free and usually easy; there's also paid parking right behind the building, so no excuse to be late.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e072048 elementor-view-framed elementor-shape-square elementor-position-inline-start elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box\" data-id=\"e072048\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\t\t\t<div class=\"elementor-icon-box-icon\">\n\t\t\t\t<span  class=\"elementor-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"ms-icons ms-check\"><\/i>\t\t\t\t<\/span>\n\t\t\t<\/div>\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tCentrally located\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\t8 minute walk from the Metro  <br data-start=\"655\" data-end=\"658\"> 5 minute walk from Atwater market, groceries, flower shops <br data-start=\"655\" data-end=\"658\"> 10 minute drive from Downtown Montreal <br data-start=\"655\" data-end=\"658\"> \n\n\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-eae0b4d elementor-view-framed elementor-shape-square elementor-position-inline-start elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box\" data-id=\"eae0b4d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\t\t\t<div class=\"elementor-icon-box-icon\">\n\t\t\t\t<span  class=\"elementor-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"ms-icons ms-check\"><\/i>\t\t\t\t<\/span>\n\t\t\t<\/div>\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tNo rentals. No nonsense. More for martinis.\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tWe include tables and chairs, already set up. Spend on what actually makes the night memorable.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c1ee31a elementor-view-framed elementor-shape-square elementor-position-inline-start elementor-mobile-position-block-start elementor-widget elementor-widget-icon-box\" data-id=\"c1ee31a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\t\t\t<div class=\"elementor-icon-box-icon\">\n\t\t\t\t<span  class=\"elementor-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"ms-icons ms-check\"><\/i>\t\t\t\t<\/span>\n\t\t\t<\/div>\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tIt\u2019s already dressed up\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tHigh ceilings, white floors, soft light\u2026 it\u2019s the Pinterest board before you start decorating.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1525521 e-con-full e-flex e-con e-parent\" data-id=\"1525521\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5e36186 elementor-widget__width-inherit elementor-arrows-position-inside elementor-pagination-position-outside elementor-widget elementor-widget-image-carousel\" data-id=\"5e36186\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;navigation&quot;:&quot;both&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;pause_on_hover&quot;:&quot;yes&quot;,&quot;pause_on_interaction&quot;:&quot;yes&quot;,&quot;autoplay_speed&quot;:5000,&quot;infinite&quot;:&quot;yes&quot;,&quot;speed&quot;:500,&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"image-carousel.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-image-carousel-wrapper swiper\" role=\"region\" aria-roledescription=\"carousel\" aria-label=\"Image Carousel\" dir=\"ltr\">\n\t\t\t<div class=\"elementor-image-carousel swiper-wrapper swiper-image-stretch\" aria-live=\"off\">\n\t\t\t\t\t\t\t\t<div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg\" alt=\"Montreal International Film Festival\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/IMG_7044-782x1043.jpg\" alt=\"IMG_7044\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"3 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/PAM_8182_websize-782x1043.jpg\" alt=\"Talia &amp; Charli\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"4 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-3058_websize-782x1043.jpg\" alt=\"Suefia Branding\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"5 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2487_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"6 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/IMG_7019-782x1043.jpg\" alt=\"IMG_7019\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"7 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2473_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"8 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2538_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"9 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/IMG_7015-782x1043.jpg\" alt=\"IMG_7015\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"10 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2548_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"11 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2490_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"12 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/485586474_18497554816048422_8751838739914366969_n-782x1043.jpg\" alt=\"485586474_18497554816048422_8751838739914366969_n\" \/><\/figure><\/div><div class=\"swiper-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"13 of 13\"><figure class=\"swiper-slide-inner\"><img decoding=\"async\" class=\"swiper-slide-image\" src=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/Pam-Kay-Montreal-Dubai-Photographer-2539_websize-782x1043.jpg\" alt=\"Pam Kay x LUMA lofts Cocktail\" \/><\/figure><\/div>\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-swiper-button elementor-swiper-button-prev\" role=\"button\" tabindex=\"0\">\n\t\t\t\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-eicon-chevron-left\" viewBox=\"0 0 1000 1000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M646 125C629 125 613 133 604 142L308 442C296 454 292 471 292 487 292 504 296 521 308 533L604 854C617 867 629 875 646 875 663 875 679 871 692 858 704 846 713 829 713 812 713 796 708 779 692 767L438 487 692 225C700 217 708 204 708 187 708 171 704 154 692 142 675 129 663 125 646 125Z\"><\/path><\/svg>\t\t\t\t\t<\/div>\n\t\t\t\t\t<div class=\"elementor-swiper-button elementor-swiper-button-next\" role=\"button\" tabindex=\"0\">\n\t\t\t\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-eicon-chevron-right\" viewBox=\"0 0 1000 1000\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M696 533C708 521 713 504 713 487 713 471 708 454 696 446L400 146C388 133 375 125 354 125 338 125 325 129 313 142 300 154 292 171 292 187 292 204 296 221 308 233L563 492 304 771C292 783 288 800 288 817 288 833 296 850 308 863 321 871 338 875 354 875 371 875 388 867 400 854L696 533Z\"><\/path><\/svg>\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"swiper-pagination\"><\/div>\n\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-638399e e-flex e-con-boxed e-con e-parent\" data-id=\"638399e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-69bc3b6 e-con-full e-flex e-con e-child\" data-id=\"69bc3b6\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-02dd1c8 elementor-widget elementor-widget-heading\" data-id=\"02dd1c8\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Types of Events We Host<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c6f8254 elementor-widget elementor-widget-text-editor\" data-id=\"c6f8254\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p data-start=\"136\" data-end=\"253\">Luma Lofts is a natural-light event space in Montreal designed for intimate gatherings of up to 40 guests, including:<\/p><ul data-start=\"255\" data-end=\"425\"><li data-start=\"255\" data-end=\"284\"><p data-start=\"257\" data-end=\"284\"><strong data-start=\"257\" data-end=\"282\">Bridal &amp; Baby Showers<\/strong><\/p><\/li><li data-start=\"285\" data-end=\"318\"><p data-start=\"287\" data-end=\"318\"><strong data-start=\"287\" data-end=\"316\">Dinners &amp; Cocktail Events<\/strong><\/p><\/li><li data-start=\"319\" data-end=\"357\"><p data-start=\"321\" data-end=\"357\"><strong data-start=\"321\" data-end=\"355\">Networking &amp; Corporate Meetups<\/strong><\/p><\/li><li data-start=\"358\" data-end=\"394\"><p data-start=\"360\" data-end=\"394\"><strong data-start=\"360\" data-end=\"392\">Workshops &amp; Creative Classes<\/strong><\/p><\/li><li data-start=\"395\" data-end=\"425\"><p data-start=\"397\" data-end=\"425\"><strong data-start=\"397\" data-end=\"425\">Yoga &amp; Wellness Sessions<\/strong><\/p><\/li><\/ul><p data-start=\"427\" data-end=\"498\">Tables, chairs always included. Flexible layout. Photo-ready space.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a89af9f e-con-full e-flex e-con e-child\" data-id=\"a89af9f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;video&quot;,&quot;background_video_link&quot;:&quot;https:\\\/\\\/lumalofts.ca\\\/wp-content\\\/uploads\\\/video-output-376423F7-9086-4336-98AA-C6085AAB74B8-1.mov&quot;,&quot;background_play_on_mobile&quot;:&quot;yes&quot;,&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t<div class=\"elementor-background-video-container\">\n\t\t\t\t\t\t\t<video class=\"elementor-background-video-hosted\" role=\"presentation\" autoplay muted playsinline loop><\/video>\n\t\t\t\t\t<\/div>\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a0d25b1 darkbg e-flex e-con-boxed e-con e-parent\" data-id=\"a0d25b1\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-84a22cb e-con-full e-flex e-con e-child\" data-id=\"84a22cb\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5080e12 elementor-widget elementor-widget-heading\" data-id=\"5080e12\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<div class=\"elementor-heading-title elementor-size-default\">I KNOW YOU WANT TO...<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-375a7f0 elementor-widget__width-initial elementor-widget elementor-widget-heading\" data-id=\"375a7f0\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Book the space everyone will keep talking about.<\/h3>\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b64302b e-con-full e-flex e-con e-child\" data-id=\"b64302b\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-05c18f9 elementor-widget__width-initial elementor-widget elementor-widget-heading\" data-id=\"05c18f9\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<div class=\"elementor-heading-title elementor-size-default\">Let\u2019s talk about your event. Whether it\u2019s a shower, a dinner, or a workshop, we\u2019ll help you make it look and feel effortless.<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0a8d7c4 e-con-full e-flex e-con e-child\" data-id=\"0a8d7c4\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5e4c834 elementor-align-center elementor-widget elementor-widget-button\" data-id=\"5e4c834\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"button.default\">\n\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"\/contact\/\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t<span class=\"elementor-button-icon\">\n\t\t\t\t<i aria-hidden=\"true\" class=\"ms-icons ms-f-long-arrow-right\"><\/i>\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Get Started Now!<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3c5e23b e-con-full e-flex e-con e-parent\" data-id=\"3c5e23b\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;mauve_ext_is_background_parallax&quot;:&quot;false&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ebb60a elementor-widget elementor-widget-html\" data-id=\"4ebb60a\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;mauve_hidepaged&quot;:&quot;false&quot;}\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Luma Lofts \u2014 Event Pricing Calculator<\/title>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:ital,wght@0,400;0,500;0,700&family=Playfair+Display:wght@400;500;600;700&display=swap\" rel=\"stylesheet\">\n<style>\n  *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\n  :root{\n    --bg:#FAF8F5;--dark:#2C2824;--cream:#FAF8F5;--gold:#8B7355;\n    --border:#EDEAE6;--muted:#999;--green:#6B8F71;--teal:#4A6670;\n    --amber:#C4956A;--light-border:#F5F3F0;\n  }\n  \/* Scoped reset \u2014 prevent WordPress theme from breaking layout *\/\n  .luma-calc, .luma-calc *, .luma-calc *::before, .luma-calc *::after{\n    box-sizing:border-box;\n  }\n  .luma-calc{\n    font-family:'DM Sans','Helvetica Neue',sans-serif;\n    color:var(--dark);background:var(--bg);\n    max-width:100%;overflow-x:hidden;\n    position:relative;line-height:1.5;\n    -webkit-font-smoothing:antialiased;\n  }\n  .luma-calc *{font-family:inherit}\n  .luma-body{max-width:680px;margin:0 auto;padding:24px 16px 80px}\n  .luma-card{\n    background:#fff;border-radius:16px;padding:20px 24px;margin-bottom:16px;\n    box-shadow:0 1px 3px rgba(0,0,0,.04);\n  }\n  .luma-label{\n    font-size:13px;font-weight:700;letter-spacing:1.5px;\n    text-transform:uppercase;color:var(--gold);margin-bottom:12px;\n  }\n  .guest-row{display:flex;align-items:center;gap:16px;margin-top:12px}\n  .guest-row input[type=range]{\n    flex:1;height:6px;-webkit-appearance:none;appearance:none;\n    background:var(--border);border-radius:3px;outline:none;\n  }\n  .guest-row input[type=range]::-webkit-slider-thumb{\n    -webkit-appearance:none;width:22px;height:22px;border-radius:50%;\n    background:var(--gold);cursor:pointer;border:2px solid #fff;\n    box-shadow:0 1px 4px rgba(0,0,0,.2);\n  }\n  .guest-row input[type=range]::-moz-range-thumb{\n    width:22px;height:22px;border-radius:50%;\n    background:var(--gold);cursor:pointer;border:2px solid #fff;\n    box-shadow:0 1px 4px rgba(0,0,0,.2);\n  }\n  .guest-row input[type=range]::-moz-range-track{\n    background:var(--border);height:6px;border-radius:3px;\n  }\n  .guest-badge{\n    background:var(--dark);color:var(--cream);border-radius:10px;\n    padding:8px 16px;font-weight:700;font-size:18px;min-width:52px;text-align:center;\n  }\n  .table-hint{font-size:13px;color:var(--muted);margin-top:8px}\n  .pkg-card{\n    background:#fff;border:2px solid var(--border);border-radius:16px;\n    padding:0;cursor:pointer;text-align:left;transition:all .2s;\n    box-shadow:0 1px 3px rgba(0,0,0,.04);margin-bottom:12px;width:100%;\n    font-family:inherit;display:block;\n  }\n  .pkg-card.selected{box-shadow:0 4px 16px rgba(0,0,0,.06)}\n  .pkg-card .pkg-img{\n    width:100%;height:180px;object-fit:cover;display:block;\n    background:var(--border);border-radius:14px 14px 0 0;\n  }\n  .pkg-card .pkg-img-placeholder{\n    width:100%;height:180px;display:flex;align-items:center;justify-content:center;\n    background:linear-gradient(135deg,#EDEAE6 0%,#DDD8D2 100%);\n    font-size:12px;color:var(--muted);letter-spacing:1px;text-transform:uppercase;\n    border-radius:14px 14px 0 0;\n  }\n  .pkg-card .pkg-body{padding:16px 20px 20px}\n  .pkg-card .pkg-top{display:flex;justify-content:space-between;align-items:flex-start}\n  .pkg-card .pkg-info{min-width:0;flex:1}\n  .pkg-card .pkg-tier{font-size:10px;letter-spacing:2px;text-transform:uppercase;font-weight:700;margin-bottom:4px}\n  .pkg-card .pkg-name{font-family:'Playfair Display',Georgia,serif;font-size:20px;font-weight:600;color:var(--dark)}\n  .pkg-card .pkg-desc{font-size:13px;color:var(--muted);margin-top:4px;line-height:1.5}\n  .pkg-card .pkg-includes{font-size:12px;color:var(--gold);margin-top:10px;line-height:1.6}\n  .pkg-card .pkg-price-col{flex-shrink:0;margin-left:16px;text-align:right}\n  .pkg-card .pkg-price{\n    font-family:'Playfair Display',Georgia,serif;font-size:24px;font-weight:600;\n    white-space:nowrap;\n  }\n  .pkg-card .pkg-tax-note{font-size:11px;color:#bbb}\n  .pkg-card .pkg-savings{font-size:11px;color:var(--green);font-weight:600;margin-top:2px}\n  .addon-img{\n    width:52px;min-width:52px;max-width:52px;height:52px;min-height:52px;max-height:52px;\n    border-radius:10px;object-fit:cover;flex-shrink:0;\n    background:var(--border);\n  }\n  .addon-img-placeholder{\n    width:52px;height:52px;border-radius:10px;flex-shrink:0;\n    background:linear-gradient(135deg,#EDEAE6 0%,#DDD8D2 100%);\n    display:flex;align-items:center;justify-content:center;font-size:18px;\n  }\n  .addon-row{\n    display:flex;align-items:center;justify-content:space-between;\n    padding:12px 0;border-bottom:1px solid var(--light-border);cursor:pointer;\n  }\n  .addon-row:last-child{border-bottom:none}\n  .addon-left{display:flex;align-items:center;gap:12px;min-width:0;flex:1}\n  .addon-row input[type=checkbox]{accent-color:var(--gold);width:18px;height:18px;cursor:pointer}\n  .addon-name{font-size:14px;font-weight:500}\n  .addon-desc{font-size:12px;color:var(--muted)}\n  .addon-price{font-size:14px;font-weight:600;flex-shrink:0;white-space:nowrap}\n  .addon-price.custom{color:var(--amber)}\n  .hours-row{display:flex;justify-content:space-between;align-items:center}\n  .hours-controls{display:flex;align-items:center;gap:12px}\n  .hour-btn{\n    width:32px;height:32px;border-radius:8px;border:1px solid #ddd;\n    background:#fff;cursor:pointer;font-size:16px;font-family:inherit;\n    display:flex;align-items:center;justify-content:center;\n  }\n  .hour-val{font-weight:700;font-size:16px;min-width:20px;text-align:center}\n  .total-card{\n    background:var(--dark);color:var(--cream);border-radius:16px;\n    padding:24px;margin-bottom:16px;\n  }\n  .total-row{display:flex;justify-content:space-between;align-items:center}\n  .total-sub{font-size:14px;opacity:.7}\n  .total-sub-val{font-size:18px;font-weight:600}\n  .total-tax{font-size:13px;opacity:.5}\n  .total-tax-val{font-size:14px;opacity:.7}\n  .total-divider{border-bottom:1px solid rgba(255,255,255,.15);margin:12px 0 16px}\n  .total-label{font-family:'Playfair Display',Georgia,serif;font-size:16px}\n  .total-amount{font-family:'Playfair Display',Georgia,serif;font-size:28px;font-weight:600}\n  .custom-quote-note{\n    margin-top:12px;padding:10px 14px;background:rgba(196,149,106,.15);\n    border-radius:8px;font-size:13px;color:var(--amber);\n  }\n  .fine-print{\n    font-size:12px;color:#bbb;text-align:center;line-height:1.6;padding:0 12px;\n  }\n  .day-btn,.block-btn{\n    flex:1;min-width:0;padding:12px 8px;border:2px solid var(--border);border-radius:12px;\n    background:#fff;cursor:pointer;text-align:center;transition:all .2s;font-family:inherit;\n  }\n  .day-btn .day-label,.block-btn .block-label{font-size:13px;font-weight:600;color:var(--dark)}\n  .day-btn .day-price,.block-btn .block-price{font-size:12px;color:var(--muted);margin-top:2px}\n  .day-btn.selected,.block-btn.selected{border-color:var(--gold);background:rgba(139,115,85,.06)}\n  .day-btn.selected .day-label,.block-btn.selected .block-label{color:var(--gold)}\n  .day-btn:hover,.block-btn:hover{border-color:#ccc}\n  \/* \u2500\u2500 BOOKING FORM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  .booking-cta{\n    width:100%;padding:18px 24px;border:none;border-radius:14px;cursor:pointer;\n    font-family:'Playfair Display',Georgia,serif;font-size:18px;font-weight:600;\n    background:var(--gold);color:var(--cream);margin-bottom:16px;\n    transition:all .3s ease;letter-spacing:.3px;\n    box-shadow:0 4px 16px rgba(139,115,85,.25);\n  }\n  .booking-cta:hover{background:#7A6548;transform:translateY(-1px);box-shadow:0 6px 20px rgba(139,115,85,.35)}\n  .booking-cta:active{transform:translateY(0)}\n  .booking-form{\n    overflow:hidden;max-height:0;opacity:0;\n    transition:max-height .5s ease,opacity .4s ease,margin .3s ease;margin-bottom:0;\n  }\n  .booking-form.open{max-height:900px;opacity:1;margin-bottom:16px}\n  .booking-form-inner{\n    background:#fff;border-radius:16px;padding:24px;\n    box-shadow:0 1px 3px rgba(0,0,0,.04);border:2px solid var(--gold);\n  }\n  .form-row{margin-bottom:16px}\n  .form-row:last-child{margin-bottom:0}\n  .form-row label{display:block;font-size:13px;font-weight:600;color:var(--dark);margin-bottom:6px}\n  .form-row label .req{color:var(--amber);margin-left:2px}\n  .form-row input,.form-row textarea,.form-row select{\n    width:100%;padding:12px 14px;border:1.5px solid var(--border);\n    border-radius:10px;font-size:14px;font-family:inherit;\n    color:var(--dark);background:#FAFAF8;transition:border-color .2s,box-shadow .2s;outline:none;\n  }\n  .form-row input:focus,.form-row textarea:focus,.form-row select:focus{\n    border-color:var(--gold);box-shadow:0 0 0 3px rgba(139,115,85,.1);\n  }\n  .form-row input::placeholder,.form-row textarea::placeholder{color:#ccc}\n  .form-row textarea{resize:vertical;min-height:80px}\n  .form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}\n  @media(max-width:480px){.form-grid{grid-template-columns:1fr}}\n  .form-row select{\n    appearance:none;\n    background-image:url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23999' stroke-width='1.5' fill='none'\/%3E%3C\/svg%3E\");\n    background-repeat:no-repeat;background-position:right 14px center;padding-right:36px;\n  }\n  .form-summary{\n    background:var(--bg);border-radius:10px;padding:14px 16px;\n    margin-bottom:16px;font-size:13px;line-height:1.7;border:1px solid var(--border);\n  }\n  .form-summary strong{color:var(--gold)}\n  .submit-btn{\n    width:100%;padding:16px 24px;border:none;border-radius:12px;cursor:pointer;\n    font-family:'DM Sans',sans-serif;font-size:15px;font-weight:700;\n    background:var(--dark);color:var(--cream);transition:all .2s;letter-spacing:.5px;\n  }\n  .submit-btn:hover{background:#3D3630}\n  .submit-btn:disabled{opacity:.5;cursor:not-allowed}\n  .submit-btn .spinner{\n    display:inline-block;width:16px;height:16px;\n    border:2px solid rgba(255,255,255,.3);border-top-color:#fff;\n    border-radius:50%;animation:spin .6s linear infinite;\n    vertical-align:middle;margin-right:8px;\n  }\n  @keyframes spin{to{transform:rotate(360deg)}}\n  .form-success{text-align:center;padding:32px 20px}\n  .form-success .check{\n    width:56px;height:56px;border-radius:50%;background:var(--green);color:#fff;\n    display:inline-flex;align-items:center;justify-content:center;font-size:28px;margin-bottom:16px;\n  }\n  .form-success h3{font-family:'Playfair Display',Georgia,serif;font-size:22px;font-weight:600;margin-bottom:8px}\n  .form-success p{font-size:14px;color:var(--muted);line-height:1.6}\n  .form-error{\n    background:rgba(220,53,69,.08);border:1px solid rgba(220,53,69,.2);\n    border-radius:8px;padding:10px 14px;font-size:13px;color:#c0392b;\n    margin-bottom:12px;display:none;\n  }\n  .form-row input.invalid,.form-row textarea.invalid,.form-row select.invalid{\n    border-color:#c0392b;background:rgba(220,53,69,.03);\n  }\n  .form-row input.invalid:focus,.form-row textarea.invalid:focus,.form-row select.invalid:focus{\n    box-shadow:0 0 0 3px rgba(220,53,69,.1);\n  }\n  .field-error{font-size:11px;color:#c0392b;margin-top:4px;display:none}\n\n  \/* \u2500\u2500 Availability Calendar \u2500\u2500 *\/\n  .cal-wrap{margin-top:16px}\n  .cal-nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}\n  .cal-nav button{background:none;border:1px solid var(--border);border-radius:8px;padding:6px 14px;cursor:pointer;font-size:14px;font-family:inherit;color:var(--dark)}\n  .cal-nav button:hover{background:var(--sand)}\n  .cal-month{font-weight:700;font-size:15px;color:var(--dark)}\n  .cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;text-align:center}\n  .cal-header{font-size:11px;font-weight:600;color:var(--muted);padding:4px 0;text-transform:uppercase}\n  .cal-day{\n    aspect-ratio:1;display:flex;align-items:center;justify-content:center;\n    border-radius:10px;font-size:13px;cursor:pointer;position:relative;\n    border:2px solid transparent;transition:all .15s;\n  }\n  .cal-day:hover:not(.cal-past):not(.cal-empty){background:var(--sand)}\n  .cal-day.cal-empty{cursor:default}\n  .cal-day.cal-past{color:#ccc;cursor:default}\n  .cal-day.cal-today{font-weight:700;color:var(--gold)}\n  .cal-day.cal-selected{border-color:var(--gold);background:rgba(139,115,85,.1);font-weight:700}\n  .cal-day.cal-busy-full{background:#f5e6e6;color:#c0392b;cursor:not-allowed;text-decoration:line-through}\n  .cal-day.cal-busy-partial{background:#fef3e2;color:#b8860b}\n  .cal-day .cal-dot{\n    position:absolute;bottom:3px;left:50%;transform:translateX(-50%);\n    width:5px;height:5px;border-radius:50%;\n  }\n  .cal-day .cal-dot.dot-busy{background:#c0392b}\n  .cal-day .cal-dot.dot-partial{background:#daa520}\n  .cal-day .cal-dot.dot-free{background:#6B8F71}\n  .cal-legend{display:flex;gap:16px;margin-top:10px;justify-content:center;flex-wrap:wrap}\n  .cal-legend-item{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--muted)}\n  .cal-legend-dot{width:8px;height:8px;border-radius:50%}\n  .cal-loading{text-align:center;padding:40px 0;color:var(--muted);font-size:13px}\n<\/style>\n<\/head>\n<body>\n<div class=\"luma-calc\" id=\"lumaCalc\">\n  <div class=\"luma-body\">\n    <!-- Day & Time Block -->\n    <div class=\"luma-card\">\n      <div class=\"luma-label\">When is your event?<\/div>\n      <div id=\"calendarWrap\" class=\"cal-wrap\">\n        <div class=\"cal-nav\">\n          <button onclick=\"calNav(-1)\">\u2190 Prev<\/button>\n          <span class=\"cal-month\" id=\"calMonthLabel\"><\/span>\n          <button onclick=\"calNav(1)\">Next \u2192<\/button>\n        <\/div>\n        <div class=\"cal-grid\" id=\"calGrid\"><\/div>\n        <div class=\"cal-legend\">\n          <div class=\"cal-legend-item\"><div class=\"cal-legend-dot\" style=\"background:#6B8F71\"><\/div> Available<\/div>\n          <div class=\"cal-legend-item\"><div class=\"cal-legend-dot\" style=\"background:#daa520\"><\/div> Partial<\/div>\n          <div class=\"cal-legend-item\"><div class=\"cal-legend-dot\" style=\"background:#c0392b\"><\/div> Booked<\/div>\n        <\/div>\n      <\/div>\n      <div id=\"selectedDateDisplay\" class=\"table-hint\" style=\"margin-top:12px;font-weight:600\"><\/div>\n      <div id=\"daySelector\" style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;display:none\"><\/div>\n      <div id=\"blockSelector\" style=\"display:flex;gap:8px;flex-wrap:wrap;margin-top:8px\"><\/div>\n      <div class=\"table-hint\" id=\"blockHint\" style=\"margin-top:10px\"><\/div>\n    <\/div>\n\n    <!-- Guest Count -->\n    <div class=\"luma-card\">\n      <div class=\"luma-label\">Number of Guests<\/div>\n      <div class=\"guest-row\">\n        <input type=\"range\" id=\"guestSlider\" min=\"10\" max=\"40\" value=\"30\">\n        <div class=\"guest-badge\" id=\"guestBadge\">30<\/div>\n      <\/div>\n      <div class=\"table-hint\" id=\"tableHint\">\u2248 5 rectangular 6ft tables<\/div>\n    <\/div>\n\n    <!-- Package Mode -->\n    <div id=\"packageMode\">\n      <div id=\"packageCards\"><\/div>\n      <div class=\"luma-card\" id=\"packageAddOns\" style=\"display:none\">\n        <div class=\"luma-label\">Add-Ons<\/div>\n        <div id=\"packageAddOnList\"><\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Extra Hours -->\n    <div class=\"luma-card\" id=\"extraHoursCard\">\n      <div class=\"hours-row\">\n        <div>\n          <div class=\"addon-name\">\u23f0 Extra Hours<\/div>\n          <div class=\"addon-desc\" id=\"extraHoursDesc\">$125 per additional hour beyond 5h<\/div>\n        <\/div>\n        <div class=\"hours-controls\">\n          <button class=\"hour-btn\" onclick=\"changeHours(-1)\">\u2212<\/button>\n          <span class=\"hour-val\" id=\"hourVal\">0<\/span>\n          <button class=\"hour-btn\" onclick=\"changeHours(1)\">+<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Cocktail Tables -->\n    <div class=\"luma-card\">\n      <div class=\"hours-row\">\n        <div>\n          <div class=\"addon-name\">\ud83c\udf78 Cocktail Tables<\/div>\n          <div class=\"addon-desc\">High-top cocktail tables \u00b7 $40 each (max 4)<\/div>\n        <\/div>\n        <div class=\"hours-controls\">\n          <button class=\"hour-btn\" onclick=\"changeCocktail(-1)\">\u2212<\/button>\n          <span class=\"hour-val\" id=\"cocktailVal\">0<\/span>\n          <button class=\"hour-btn\" onclick=\"changeCocktail(1)\">+<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Total -->\n    <div class=\"total-card\" id=\"totalCard\">\n      <div class=\"total-row\" style=\"margin-bottom:12px\">\n        <span class=\"total-sub\">Subtotal<\/span>\n        <span class=\"total-sub-val\" id=\"subtotalVal\">$500.00<\/span>\n      <\/div>\n      <div class=\"total-row\">\n        <span class=\"total-tax\">Tax (QST + GST \u00b7 14.975%)<\/span>\n        <span class=\"total-tax-val\" id=\"taxVal\">$74.88<\/span>\n      <\/div>\n      <div class=\"total-divider\"><\/div>\n      <div class=\"total-row\">\n        <span class=\"total-label\">Estimated Total<\/span>\n        <span class=\"total-amount\" id=\"totalVal\">$574.88<\/span>\n      <\/div>\n      <div class=\"custom-quote-note\" id=\"customQuoteNote\" style=\"display:none\">\n        \u2726 Real flowers require a custom quote \u2014 we'll connect you with our florist partner.\n      <\/div>\n    <\/div>\n\n    <!-- Reserve Your Date CTA -->\n    <button class=\"booking-cta\" id=\"bookingCta\" onclick=\"toggleBookingForm()\">\n      Request to Book \u2192\n    <\/button>\n\n    <!-- Booking Form (slides open) -->\n    <div class=\"booking-form\" id=\"bookingForm\">\n      <div class=\"booking-form-inner\">\n        <div class=\"luma-label\">Your Information<\/div>\n        <div class=\"form-summary\" id=\"formSummary\"><\/div>\n        <div class=\"form-error\" id=\"formError\"><\/div>\n        <div class=\"form-grid\">\n          <div class=\"form-row\">\n            <label>First Name <span class=\"req\">*<\/span><\/label>\n            <input type=\"text\" id=\"fFirstName\" placeholder=\"Jane\">\n          <\/div>\n          <div class=\"form-row\">\n            <label>Last Name <span class=\"req\">*<\/span><\/label>\n            <input type=\"text\" id=\"fLastName\" placeholder=\"Doe\">\n            <div class=\"field-error\" id=\"errLastName\">Last name is required<\/div>\n          <\/div>\n        <\/div>\n        <div class=\"form-row\">\n          <label>Email <span class=\"req\">*<\/span><\/label>\n          <input type=\"email\" id=\"fEmail\" placeholder=\"jane@example.com\">\n          <div class=\"field-error\" id=\"errEmail\">Please enter a valid email<\/div>\n        <\/div>\n        <div class=\"form-row\">\n          <label>Phone <span class=\"req\">*<\/span><\/label>\n          <input type=\"tel\" id=\"fPhone\" placeholder=\"(514) 555-0123\">\n          <div class=\"field-error\" id=\"errPhone\">Phone number is required<\/div>\n        <\/div>\n        <div class=\"form-grid\">\n          <div class=\"form-row\">\n            <input type=\"hidden\" id=\"fDate\">\n          <\/div>\n          <div class=\"form-row\">\n            <label>Event Type<\/label>\n            <select id=\"fEventType\">\n              <option value=\"\">Select...<\/option>\n              <option value=\"Corporate Event\">Corporate Event<\/option>\n              <option value=\"Private Party\">Private Party<\/option>\n              <option value=\"Workshop\">Workshop<\/option>\n              <option value=\"Birthday\">Birthday<\/option>\n              <option value=\"Baby Shower\">Baby Shower<\/option>\n              <option value=\"Bridal Shower\">Bridal Shower<\/option>\n              <option value=\"Holiday Party\">Holiday Party<\/option>\n              <option value=\"Other\">Other<\/option>\n            <\/select>\n          <\/div>\n        <\/div>\n        <div class=\"form-row\">\n          <label>Anything else we should know?<\/label>\n          <textarea id=\"fNotes\" placeholder=\"Tell us about your event, special requirements, dietary needs, etc.\"><\/textarea>\n        <\/div>\n        <button class=\"submit-btn\" id=\"submitBtn\" onclick=\"submitBooking()\">Submit Inquiry<\/button>\n      <\/div>\n    <\/div>\n\n    <!-- Success State -->\n    <div id=\"bookingSuccess\" style=\"display:none\">\n      <div class=\"luma-card\">\n        <div class=\"form-success\">\n          <div class=\"check\">\u2713<\/div>\n          <h3>Inquiry Received!<\/h3>\n          <p>We'll review your event details and get back to you within 24 hours with availability and a formal quote. Keep an eye on your inbox.<\/p>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- Breakdown Toggle -->\n\n    <!-- Fine Print -->\n    <div class=\"fine-print\">\n      Prices are estimates. Final pricing confirmed upon booking.<br>\n      Orders under $1,000 require payment in full. Orders $1,000+ require a 50% non-refundable deposit to reserve your date.\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(function(){\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  CONFIGURATION \u2014 Edit these values as needed     \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  \/\/ Cloudflare Worker URL (set to your deployed worker)\n  var WORKER_URL = \"https:\/\/luma-booking.purple-wind-496e.workers.dev\";\n\n  \/\/ Google Calendar availability worker URL\n  var CALENDAR_WORKER_URL = \"https:\/\/luma-calendar.purple-wind-496e.workers.dev\";\n\n  \/\/ Tax rate (QST + GST combined)\n  const TAX_RATE = 0.14975;\n\n  \/\/ \u2500\u2500 TIME BLOCKS & PRICING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ Weekday = flexible timing, weekends = fixed blocks\n  const DAY_OPTIONS = [\n    { key: \"weekday\",  label: \"Weekday\",  sublabel: \"Mon\u2013Fri\" },\n    { key: \"sunday\",   label: \"Sunday\",   sublabel: \"\" },\n    { key: \"saturday\", label: \"Saturday\", sublabel: \"\" },\n  ];\n\n  const BLOCK_OPTIONS = {\n    weekday:  [\n      { key: \"standard\", label: \"Standard\", sublabel: \"5 hours \u00b7 flexible timing\", price: 500, hours: 5 }\n    ],\n    sunday:   [\n      { key: \"standard\", label: \"Standard\", sublabel: \"5 hours \u00b7 flexible timing\", price: 575, hours: 5 }\n    ],\n    saturday: [\n      { key: \"morning\",  label: \"Morning\",  sublabel: \"10am \u2013 3pm\", price: 650,  hours: 5 },\n      { key: \"evening\",  label: \"Evening\",  sublabel: \"5pm \u2013 10pm\", price: 700,  hours: 5 },\n      { key: \"fullday\",  label: \"Full Day\", sublabel: \"10am \u2013 10pm\", price: 1200, hours: 10 },\n    ],\n  };\n\n  const EXTRA_HOUR_RATE = 125;\n\n  \/\/ \u2500\u2500 IMAGES \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ Package card photos (wide aspect ratio, ~680\u00d7240px recommended)\n  const PACKAGE_IMAGES = {\n    base:       \"https:\/\/lumalofts.ca\/wp-content\/uploads\/2023\/04\/IMG_1302-scaled.jpg\",\n    essentials: \"https:\/\/lumalofts.ca\/wp-content\/uploads\/2023\/04\/IMG_1302-scaled.jpg\",\n    elevated:   \"https:\/\/lumalofts.ca\/wp-content\/uploads\/2023\/04\/IMG_1302-scaled.jpg\",\n  };\n\n  \/\/ Add-on thumbnails (square, ~80\u00d780px recommended)\n  \/\/ Leave \"\" to keep the emoji icon instead\n  const ADDON_IMAGES = {\n    setup:          \"\",  \/\/ \ud83d\udd27 Setup & Teardown\n    tablecloths:    \"\",  \/\/ \ud83e\ude91 Tablecloths\n    napkins:        \"\",  \/\/ \ud83e\uddfb Cloth Napkins\n    plates:         \"\",  \/\/ \ud83c\udf7d Plates\n    utensils:       \"\",  \/\/ \ud83e\udd44 Utensils\n    glasses:        \"\",  \/\/ \ud83e\udd42 Glassware\n    lamps:          \"\",  \/\/ \ud83d\udca1 Table Lamps\n    budVases:       \"\",  \/\/ \ud83c\udf38 Bud Vases\n    fauxFlorals:    \"\",  \/\/ \ud83d\udc90 Faux Florals\n    photobooth:     \"\",  \/\/ \ud83d\udcf8 Photobooth\n    realFlowers:    \"\",  \/\/ \ud83c\udf39 Real Flowers\n    barService:     \"\",  \/\/ \ud83c\udf77 Bar Service\n    catering:       \"\",  \/\/ \ud83c\udf74 Catering\n    cocktailTables: \"\",  \/\/ \ud83c\udf78 Cocktail Tables\n  };\n\n  \/\/ \u2500\u2500 PACKAGES \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ basePrice is 0 because venue rental is now dynamic (set by day\/block above)\n  const PACKAGES = {\n    base: {\n      name: \"Luma Base\",\n      tier: \"DIY\",\n      description: \"Venue access with tables & chairs. You handle your own setup & teardown within your rental time.\",\n      basePrice: 0,\n      perPerson: 0,\n      includes: [],\n      color: \"#8B7355\",\n      img: PACKAGE_IMAGES.base\n    },\n    essentials: {\n      name: \"Luma Essentials\",\n      tier: \"Most Popular\",\n      description: \"Everything you need for a polished seated event.\",\n      basePrice: 0,\n      perPerson: 6,\n      includes: [\"setup\", \"tablecloths\"],\n      color: \"#6B8F71\",\n      img: PACKAGE_IMAGES.essentials\n    },\n    elevated: {\n      name: \"Luma Elevated\",\n      tier: \"Full Service\",\n      description: \"A beautifully styled event with all the details covered.\",\n      basePrice: 0,\n      perPerson: 22,\n      includes: [\"setup\", \"tablecloths\", \"napkins\", \"plates\", \"utensils\", \"glasses\", \"budVases\", \"fauxFlorals\", \"lamps\"],\n      color: \"#4A6670\",\n      img: PACKAGE_IMAGES.elevated\n    }\n  };\n\n  \/\/ \u2500\u2500 ADD-ONS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  const ADD_ONS = {\n    setup:          { name: \"Setup & Teardown\",      desc: \"We handle table & chair arrangement\",          type: \"flat\",      price: 150,  icon: \"\ud83d\udd27\", img: ADDON_IMAGES.setup },\n    tablecloths:    { name: \"Tablecloths\",           desc: \"Elegant floor-length linens\",                  type: \"perTable\",  price: 15,   icon: \"\ud83e\ude91\", img: ADDON_IMAGES.tablecloths },\n    napkins:        { name: \"Cloth Napkins (Beige)\",  desc: \"Quality fabric napkins\",                       type: \"perPerson\", price: 2,    icon: \"\ud83e\uddfb\", img: ADDON_IMAGES.napkins },\n    plates:         { name: \"Plates\",                desc: \"White ceramic dinner plates\",                   type: \"perPerson\", price: 3,    icon: \"\ud83c\udf7d\", img: ADDON_IMAGES.plates },\n    utensils:       { name: \"Utensils\",              desc: \"Fork, knife & spoon set\",                      type: \"perPerson\", price: 2.5,  icon: \"\ud83e\udd44\", img: ADDON_IMAGES.utensils },\n    glasses:        { name: \"Glassware\",             desc: \"Wine or cocktail glasses\",                      type: \"perPerson\", price: 3,    icon: \"\ud83e\udd42\", img: ADDON_IMAGES.glasses },\n    lamps:          { name: \"Table Lamps\",           desc: \"Elegant cordless lampshades (2 per table)\",     type: \"perTable\",  price: 16,   icon: \"\ud83d\udca1\", img: ADDON_IMAGES.lamps },\n    budVases:       { name: \"Bud Vases\",             desc: \"Small glass vases (1 per table)\",               type: \"perTable\",  price: 8,    icon: \"\ud83c\udf38\", img: ADDON_IMAGES.budVases },\n    fauxFlorals:    { name: \"Faux Florals\",          desc: \"Silk arrangements per table\",                   type: \"perTable\",  price: 25,   icon: \"\ud83d\udc90\", img: ADDON_IMAGES.fauxFlorals },\n    photobooth:     { name: \"Photobooth\",            desc: \"Self-serve stand, unlimited digital photos\",    type: \"flat\",      price: 175,  icon: \"\ud83d\udcf8\", img: ADDON_IMAGES.photobooth },\n    realFlowers:    { name: \"Real Flowers\",          desc: \"Custom quote from our florist partner\",         type: \"custom\",    price: 0,    icon: \"\ud83c\udf39\", img: ADDON_IMAGES.realFlowers },\n    barService:     { name: \"Bar Service\",           desc: \"We'll connect you with our bartending partner\", type: \"custom\",    price: 0,    icon: \"\ud83c\udf77\", img: ADDON_IMAGES.barService },\n    catering:       { name: \"Catering\",              desc: \"We'll connect you with our catering partner\",   type: \"custom\",    price: 0,    icon: \"\ud83c\udf74\", img: ADDON_IMAGES.catering },\n    cocktailTables: { name: \"Cocktail Tables\",       desc: \"High-top cocktail tables (max 4)\",              type: \"perUnit\",   price: 40,   icon: \"\ud83c\udf78\", img: ADDON_IMAGES.cocktailTables, maxQty: 4 }\n  };\n\n  \/\/ \u2500\u2500 BUSINESS RULES \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ These add-ons auto-enable \"Setup & Teardown\" when selected\n  const REQUIRES_SETUP = [\"plates\", \"budVases\", \"fauxFlorals\", \"realFlowers\", \"lamps\", \"napkins\", \"utensils\", \"glasses\"];\n\n  function enforceSetupDep(items) {\n    if (REQUIRES_SETUP.some(function(k) { return !!items[k]; })) {\n      items.setup = true;\n    }\n  }\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  STATE & CALCULATIONS                            \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  var state = {\n    day: \"saturday\",\n    block: \"evening\",\n    guests: 30,\n    selectedPkg: \"essentials\",\n    pkgAddOns: {},\n    extraHours: 0,\n    cocktailQty: 0,\n    formOpen: false,\n    \/\/ Calendar\n    selectedDate: null,       \/\/ \"2026-03-15\"\n    calYear: new Date().getFullYear(),\n    calMonth: new Date().getMonth(), \/\/ 0-indexed\n    availability: {},          \/\/ { \"2026-03\": [ {date, blocks}, ... ] }\n    calLoading: false,\n  };\n\n  \/\/ Get active block config\n  function activeBlock() {\n    var blocks = BLOCK_OPTIONS[state.day] || [];\n    return blocks.find(function(b) { return b.key === state.block; }) || blocks[0];\n  }\n\n  function basePrice() {\n    return activeBlock().price;\n  }\n\n  function includedHours() {\n    return activeBlock().hours;\n  }\n\n  \/\/ Table count based on physical venue layout (rectangular 6ft tables)\n  function tables() {\n    var g = state.guests;\n    if (g <= 14) return 2;\n    if (g <= 20) return 3;\n    if (g <= 28) return 4;\n    if (g <= 34) return 5;\n    return 6;\n  }\n\n  function itemCost(key) {\n    var item = ADD_ONS[key];\n    if (item.type === \"perPerson\") return item.price * state.guests;\n    if (item.type === \"perTable\")  return item.price * tables();\n    if (item.type === \"perUnit\")   return item.price * state.cocktailQty;\n    if (item.type === \"flat\")      return item.price;\n    return 0;\n  }\n\n  function calcSubtotal() {\n    var sub = basePrice();\n    var pkg = PACKAGES[state.selectedPkg];\n    if (pkg.perPerson) sub += pkg.perPerson * state.guests;\n    Object.keys(state.pkgAddOns).forEach(function(k) {\n      if (state.pkgAddOns[k] && !pkg.includes.includes(k) && ADD_ONS[k].type !== \"custom\")\n        sub += itemCost(k);\n    });\n    sub += state.extraHours * EXTRA_HOUR_RATE;\n    sub += state.cocktailQty * ADD_ONS.cocktailTables.price;\n    return sub;\n  }\n\n  \/\/ What the package's included items would cost if bought separately\n  function calcAlaCartePrice(pkg) {\n    var price = basePrice();\n    pkg.includes.forEach(function(k) {\n      if (!ADD_ONS[k]) return;\n      var a = ADD_ONS[k];\n      if (a.type === \"perPerson\")  price += a.price * state.guests;\n      else if (a.type === \"perTable\") price += a.price * tables();\n      else if (a.type === \"flat\")     price += a.price;\n    });\n    return price;\n  }\n\n  function hasCustom() {\n    return Object.keys(state.pkgAddOns).some(function(k) {\n      return state.pkgAddOns[k] && ADD_ONS[k] && ADD_ONS[k].type === \"custom\";\n    });\n  }\n\n  function getCustomNames() {\n    var names = [];\n    Object.keys(state.pkgAddOns).forEach(function(k) {\n      if (state.pkgAddOns[k] && ADD_ONS[k] && ADD_ONS[k].type === \"custom\")\n        names.push(ADD_ONS[k].name);\n    });\n    return names;\n  }\n\n  function fmt(n) {\n    return \"$\" + n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n  }\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  RENDERING                                       \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  function renderGuest() {\n    document.getElementById(\"guestBadge\").textContent = state.guests;\n    var t = tables();\n    document.getElementById(\"tableHint\").textContent = \"\u2248 \" + t + \" rectangular 6ft table\" + (t !== 1 ? \"s\" : \"\");\n  }\n\n  function renderPackages() {\n    var container = document.getElementById(\"packageCards\");\n    container.innerHTML = \"\";\n    var venuePrice = basePrice();\n\n    Object.entries(PACKAGES).forEach(function([key, pkg]) {\n      var isSelected = state.selectedPkg === key;\n      var pkgTotal = venuePrice + (pkg.perPerson ? pkg.perPerson * state.guests : 0);\n\n      var card = document.createElement(\"div\");\n      card.className = \"pkg-card\" + (isSelected ? \" selected\" : \"\");\n      card.style.borderColor = isSelected ? pkg.color : \"\";\n      card.style.boxShadow = isSelected ? \"0 4px 16px \" + pkg.color + \"22\" : \"\";\n      card.onclick = function() { state.selectedPkg = key; state.pkgAddOns = {}; render(); };\n\n      var includesHTML = \"\";\n      if (pkg.includes.length) {\n        includesHTML = '<div class=\"pkg-includes\">Includes: ' +\n          pkg.includes.map(function(k) { return ADD_ONS[k] ? ADD_ONS[k].name : k; }).join(\" \u00b7 \") + '<\/div>';\n      }\n\n      var savingsHTML = \"\";\n      if (pkg.perPerson > 0) {\n        var alaPrice = calcAlaCartePrice(pkg);\n        if (pkgTotal < alaPrice) {\n          savingsHTML = '<div class=\"pkg-savings\">Save $' + (alaPrice - pkgTotal).toLocaleString() + ' vs \u00e0 la carte<\/div>';\n        }\n      }\n\n      var imgHTML = pkg.img\n        ? '<img decoding=\"async\" class=\"pkg-img\" src=\"' + pkg.img + '\" alt=\"' + pkg.name + '\">'\n        : '<div class=\"pkg-img-placeholder\">Photo coming soon<\/div>';\n\n      card.innerHTML = imgHTML +\n        '<div class=\"pkg-body\">' +\n          '<div class=\"pkg-top\">' +\n            '<div class=\"pkg-info\">' +\n              '<div class=\"pkg-tier\" style=\"color:' + pkg.color + '\">' + pkg.tier + '<\/div>' +\n              '<div class=\"pkg-name\">' + pkg.name + '<\/div>' +\n              '<div class=\"pkg-desc\">' + pkg.description + '<\/div>' +\n            '<\/div>' +\n            '<div class=\"pkg-price-col\">' +\n              '<div class=\"pkg-price\" style=\"color:' + pkg.color + '\">$' + pkgTotal.toLocaleString() + '<\/div>' +\n              '<div class=\"pkg-tax-note\">before tax<\/div>' +\n              savingsHTML +\n            '<\/div>' +\n          '<\/div>' +\n          includesHTML +\n        '<\/div>';\n\n      container.appendChild(card);\n    });\n  }\n\n  function renderPkgAddOns() {\n    var pkg = PACKAGES[state.selectedPkg];\n    var container = document.getElementById(\"packageAddOnList\");\n    var card = document.getElementById(\"packageAddOns\");\n    var items = Object.entries(ADD_ONS).filter(function([k]) {\n      return !pkg.includes.includes(k) && k !== \"extraHour\" && k !== \"cocktailTables\";\n    });\n\n    if (!items.length) { card.style.display = \"none\"; return; }\n    card.style.display = \"\";\n    container.innerHTML = \"\";\n\n    items.forEach(function([key, item]) {\n      var isCustom = item.type === \"custom\";\n      var cost = itemCost(key);\n      var setupForced = (key === \"setup\") && REQUIRES_SETUP.some(function(k) { return !!state.pkgAddOns[k]; });\n      var isChecked = !!state.pkgAddOns[key];\n\n      var row = document.createElement(\"label\");\n      row.className = \"addon-row\";\n\n      var imgHTML = item.img\n        ? '<img decoding=\"async\" class=\"addon-img\" src=\"' + item.img + '\" alt=\"' + item.name + '\">'\n        : '<div class=\"addon-img-placeholder\">' + item.icon + '<\/div>';\n\n      var descText = item.desc;\n      if (setupForced) descText += ' \u00b7 <span style=\"color:var(--amber);font-weight:600\">Required with your selections<\/span>';\n\n      row.innerHTML =\n        '<div class=\"addon-left\">' +\n          '<input type=\"checkbox\" data-key=\"' + key + '\" ' + (isChecked ? 'checked' : '') + ' ' + (setupForced ? 'disabled' : '') + ' style=\"' + (setupForced ? 'opacity:.6' : '') + '\">' +\n          imgHTML +\n          '<div><div class=\"addon-name\">' + item.name + '<\/div>' +\n          '<div class=\"addon-desc\">' + descText + '<\/div><\/div>' +\n        '<\/div>' +\n        '<div class=\"addon-price' + (isCustom ? ' custom' : '') + '\">' +\n          (isCustom ? 'Get a quote' : '+$' + cost) +\n        '<\/div>';\n\n      row.querySelector(\"input\").addEventListener(\"change\", function() {\n        state.pkgAddOns[key] = this.checked;\n        enforceSetupDep(state.pkgAddOns);\n        render();\n      });\n\n      container.appendChild(row);\n    });\n  }\n\n  function renderTotal() {\n    var sub = calcSubtotal();\n    var tax = sub * TAX_RATE;\n    var total = sub + tax;\n    document.getElementById(\"subtotalVal\").textContent = fmt(sub);\n    document.getElementById(\"taxVal\").textContent = fmt(tax);\n    document.getElementById(\"totalVal\").textContent = fmt(total);\n\n    var noteEl = document.getElementById(\"customQuoteNote\");\n    if (hasCustom()) {\n      noteEl.innerHTML = \"\u2726 \" + getCustomNames().join(\", \") + \" \u2014 we'll connect you with our partners for a custom quote.\";\n      noteEl.style.display = \"\";\n    } else {\n      noteEl.style.display = \"none\";\n    }\n  }\n\n  function renderHours() {\n    document.getElementById(\"hourVal\").textContent = state.extraHours;\n    document.getElementById(\"cocktailVal\").textContent = state.cocktailQty;\n    var extraCard = document.getElementById(\"extraHoursCard\");\n    if (extraCard) {\n      extraCard.style.opacity = state.block === \"fullday\" ? \"0.4\" : \"1\";\n      extraCard.style.pointerEvents = state.block === \"fullday\" ? \"none\" : \"\";\n    }\n  }\n\n  function renderFormSummary() {\n    var el = document.getElementById(\"formSummary\");\n    if (!el || !state.formOpen) return;\n\n    var sub = calcSubtotal();\n    var total = sub + sub * TAX_RATE;\n    var pkg = PACKAGES[state.selectedPkg];\n    var blk = activeBlock();\n    var totalHours = includedHours() + state.extraHours;\n\n    var dayLabel = DAY_OPTIONS.find(function(d) { return d.key === state.day; }).label;\n    var blockLabel = blk.key !== \"standard\" ? \" \" + blk.label : \"\";\n\n    var html = '<strong>' + dayLabel + blockLabel + '<\/strong> \u00b7 <strong>' + pkg.name + '<\/strong> \u00b7 ' +\n      state.guests + ' guests \u00b7 ' + totalHours + 'h \u00b7 <strong>' + fmt(total) + '<\/strong> (incl. tax)';\n\n    var names = [];\n    Object.keys(state.pkgAddOns).forEach(function(k) {\n      if (state.pkgAddOns[k] && ADD_ONS[k] && !pkg.includes.includes(k))\n        names.push(ADD_ONS[k].name);\n    });\n    if (state.cocktailQty > 0) names.push(state.cocktailQty + \" cocktail table\" + (state.cocktailQty > 1 ? \"s\" : \"\"));\n    if (names.length) html += '<br>Add-ons: ' + names.join(', ');\n\n    el.innerHTML = html;\n  }\n\n  function render() {\n    renderCalendar();\n    renderDayBlock();\n    renderGuest();\n    renderPackages();\n    renderPkgAddOns();\n    renderHours();\n    renderTotal();\n    renderFormSummary();\n  }\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  USER INTERACTIONS                               \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  window.changeHours = function(d) {\n    if (state.block === \"fullday\") return; \/\/ No extra hours on full day\n    state.extraHours = Math.max(0, state.extraHours + d);\n    render();\n  };\n\n  window.changeCocktail = function(d) {\n    state.cocktailQty = Math.max(0, Math.min(4, state.cocktailQty + d));\n    render();\n  };\n\n  window.toggleBookingForm = function() {\n    state.formOpen = !state.formOpen;\n    var form = document.getElementById(\"bookingForm\");\n    var cta = document.getElementById(\"bookingCta\");\n    form.classList.toggle(\"open\", state.formOpen);\n    cta.textContent = state.formOpen ? \"Close Form \u00d7\" : \"Request to book \u2192\";\n    if (state.formOpen) renderFormSummary();\n  };\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  FORM VALIDATION & SUBMISSION                    \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  \/\/ Helper: show field error\n  function showFieldError(fieldId, errId, message) {\n    document.getElementById(fieldId).classList.add(\"invalid\");\n    var errEl = document.getElementById(errId);\n    errEl.textContent = message;\n    errEl.style.display = \"block\";\n  }\n\n  \/\/ Helper: clear all field errors\n  function clearAllErrors() {\n    document.getElementById(\"formError\").style.display = \"none\";\n    [\"fFirstName\", \"fLastName\", \"fEmail\", \"fPhone\"].forEach(function(id) {\n      document.getElementById(id).classList.remove(\"invalid\");\n    });\n    [\"errFirstName\", \"errLastName\", \"errEmail\", \"errPhone\"].forEach(function(id) {\n      document.getElementById(id).style.display = \"none\";\n    });\n  }\n\n  \/\/ Helper: attach auto-clear on input\n  function attachAutoClear() {\n    [\"fFirstName\", \"fLastName\", \"fEmail\", \"fPhone\"].forEach(function(id) {\n      document.getElementById(id).addEventListener(\"input\", function() {\n        this.classList.remove(\"invalid\");\n        var errId = \"err\" + id.charAt(1).toUpperCase() + id.slice(2);\n        var errEl = document.getElementById(errId);\n        if (errEl) errEl.style.display = \"none\";\n      }, { once: true });\n    });\n  }\n\n  window.submitBooking = async function() {\n    var firstName = document.getElementById(\"fFirstName\").value.trim();\n    var lastName  = document.getElementById(\"fLastName\").value.trim();\n    var email     = document.getElementById(\"fEmail\").value.trim();\n    var phone     = document.getElementById(\"fPhone\").value.trim();\n    var btn       = document.getElementById(\"submitBtn\");\n\n    clearAllErrors();\n\n    \/\/ Validate\n    var errors = [];\n    if (!firstName)                                  { showFieldError(\"fFirstName\", \"errFirstName\", \"First name is required\"); errors.push(1); }\n    if (!lastName)                                   { showFieldError(\"fLastName\",  \"errLastName\",  \"Last name is required\");  errors.push(1); }\n    if (!email)                                      { showFieldError(\"fEmail\",     \"errEmail\",     \"Email is required\");      errors.push(1); }\n    else if (!\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)) { showFieldError(\"fEmail\", \"errEmail\", \"Please enter a valid email\"); errors.push(1); }\n    if (!phone)                                      { showFieldError(\"fPhone\",     \"errPhone\",     \"Phone number is required\");     errors.push(1); }\n    else if (!\/^[\\d\\s\\(\\)\\-\\+\\.]{7,20}$\/.test(phone))   { showFieldError(\"fPhone\", \"errPhone\", \"Please enter a valid phone number\"); errors.push(1); }\n\n    if (errors.length) {\n      document.getElementById(\"formError\").textContent = \"Please fix the highlighted fields above.\";\n      document.getElementById(\"formError\").style.display = \"block\";\n      var firstInvalid = document.querySelector(\".invalid\");\n      if (firstInvalid) firstInvalid.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n      attachAutoClear();\n      return;\n    }\n\n    \/\/ Build payload\n    var event = buildEventPayload();\n    var payload = {\n      client: { firstName: firstName, lastName: lastName, email: email, phone: phone },\n      event: event\n    };\n\n    btn.disabled = true;\n    btn.innerHTML = '<span class=\"spinner\"><\/span> Submitting...';\n\n    try {\n      if (WORKER_URL && WORKER_URL.indexOf(\"YOUR-SUBDOMAIN\") === -1) {\n        var resp = await fetch(WORKER_URL, {\n          method: \"POST\",\n          headers: { \"Content-Type\": \"application\/json\" },\n          body: JSON.stringify(payload)\n        });\n        var result = await resp.json();\n        console.log(\"\ud83d\udd0d VSCO Response:\", JSON.stringify(result, null, 2));\n        if (!resp.ok) throw new Error(result.error || result.detail || \"Submission failed\");\n      } else {\n        await new Promise(function(r) { setTimeout(r, 1200); });\n        console.log(\"\ud83d\udccb Luma booking payload (demo mode):\", JSON.stringify(payload, null, 2));\n      }\n      document.getElementById(\"bookingForm\").classList.remove(\"open\");\n      document.getElementById(\"bookingCta\").style.display = \"none\";\n      document.getElementById(\"bookingSuccess\").style.display = \"\";\n    } catch(err) {\n      document.getElementById(\"formError\").textContent = err.message || \"Something went wrong. Please try again or email us directly.\";\n      document.getElementById(\"formError\").style.display = \"block\";\n    } finally {\n      btn.disabled = false;\n      btn.innerHTML = \"Submit Inquiry\";\n    }\n  };\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  API PAYLOAD BUILDER                             \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  function buildEventPayload() {\n    var sub = calcSubtotal();\n    var tax = sub * TAX_RATE;\n    var pkg = PACKAGES[state.selectedPkg];\n    var blk = activeBlock();\n\n    var addOns = [];\n    Object.keys(state.pkgAddOns).forEach(function(k) {\n      if (!state.pkgAddOns[k]) return;\n      var a = ADD_ONS[k];\n      if (a.type === \"custom\" || pkg.includes.includes(k)) return;\n\n      var units = 1, unitPrice = a.price, detail = \"\";\n      if (a.type === \"perPerson\") { units = state.guests; detail = state.guests + \" \u00d7 $\" + a.price; }\n      if (a.type === \"perTable\")  { units = tables();      detail = tables() + \" \u00d7 $\" + a.price; }\n      if (a.type === \"flat\")      { detail = \"flat rate\"; }\n\n      addOns.push({ name: a.name, unitPrice: unitPrice, units: units, cost: itemCost(k), detail: detail });\n    });\n\n    return {\n      day: state.day,\n      block: state.block,\n      blockLabel: blk.label || blk.key,\n      venuePrice: blk.price,\n      includedHours: blk.hours,\n      packageKey: state.selectedPkg,\n      packageName: pkg.name,\n      packagePerPerson: pkg.perPerson || 0,\n      packageTotal: blk.price + (pkg.perPerson ? pkg.perPerson * state.guests : 0),\n      guests: state.guests,\n      tables: tables(),\n      addOns: addOns,\n      extraHours: state.extraHours,\n      cocktailTables: state.cocktailQty,\n      hasRealFlowers: !!state.pkgAddOns.realFlowers,\n      hasBarService: !!state.pkgAddOns.barService,\n      hasCatering: !!state.pkgAddOns.catering,\n      subtotal: sub,\n      tax: tax,\n      total: sub + tax,\n      notes: document.getElementById(\"fNotes\") ? document.getElementById(\"fNotes\").value.trim() : \"\",\n      date: state.selectedDate || null,\n      eventType: document.getElementById(\"fEventType\") ? document.getElementById(\"fEventType\").value : null\n    };\n  }\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  AVAILABILITY CALENDAR                           \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  const MONTH_NAMES = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"];\n  const DAY_NAMES = [\"Sun\",\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\"];\n\n  function calMonthKey(y, m) { return y + \"-\" + String(m + 1).padStart(2, \"0\"); }\n\n  async function fetchAvailability(year, month) {\n    var key = calMonthKey(year, month);\n    if (state.availability[key]) return; \/\/ already cached\n    if (!CALENDAR_WORKER_URL || CALENDAR_WORKER_URL.indexOf(\"YOUR-SUBDOMAIN\") !== -1) return;\n\n    state.calLoading = true;\n    renderCalendar();\n\n    try {\n      var resp = await fetch(CALENDAR_WORKER_URL + \"\/availability?month=\" + key);\n      var data = await resp.json();\n      state.availability[key] = data.busyDates || [];\n    } catch (e) {\n      console.error(\"Calendar fetch error:\", e);\n      state.availability[key] = [];\n    }\n\n    state.calLoading = false;\n    renderCalendar();\n  }\n\n  function getBusyInfo(dateStr) {\n    var key = dateStr.substring(0, 7); \/\/ \"2026-03\"\n    var monthData = state.availability[key] || [];\n    var entry = monthData.find(function(d) { return d.date === dateStr; });\n    return entry ? entry.blocks : [];\n  }\n\n  function getDayOfWeek(dateStr) {\n    var d = new Date(dateStr + \"T12:00:00\");\n    return d.getDay(); \/\/ 0=Sun, 6=Sat\n  }\n\n  function getDayKey(dateStr) {\n    var dow = getDayOfWeek(dateStr);\n    if (dow === 6) return \"saturday\";\n    if (dow === 0) return \"sunday\";\n    return \"weekday\";\n  }\n\n  function isDateFullyBooked(dateStr) {\n    var blocks = getBusyInfo(dateStr);\n    var dayKey = getDayKey(dateStr);\n\n    if (blocks.includes(\"fullday\")) return true;\n\n    \/\/ For Saturday, check if all bookable blocks are taken\n    if (dayKey === \"saturday\") {\n      return blocks.includes(\"morning\") && blocks.includes(\"evening\");\n    }\n\n    \/\/ Weekday\/Sunday: if morning or evening is marked busy, that standard block is gone\n    \/\/ Since there's only one \"standard\" block, any busy = fully booked\n    \/\/ But we treat it more loosely \u2014 if the busy period doesn't cover the full day, it's partial\n    return blocks.includes(\"fullday\");\n  }\n\n  function isDatePartiallyBooked(dateStr) {\n    var blocks = getBusyInfo(dateStr);\n    if (blocks.length === 0) return false;\n    return !isDateFullyBooked(dateStr);\n  }\n\n  function getAvailableBlocks(dateStr) {\n    var dayKey = getDayKey(dateStr);\n    var busyBlocks = getBusyInfo(dateStr);\n    var allBlocks = BLOCK_OPTIONS[dayKey] || [];\n\n    if (busyBlocks.includes(\"fullday\")) return [];\n\n    return allBlocks.filter(function(b) {\n      if (b.key === \"fullday\") {\n        \/\/ Full day only available if neither morning nor evening is booked\n        return !busyBlocks.includes(\"morning\") && !busyBlocks.includes(\"evening\");\n      }\n      return !busyBlocks.includes(b.key);\n    });\n  }\n\n  function selectDate(dateStr) {\n    var dayKey = getDayKey(dateStr);\n    var available = getAvailableBlocks(dateStr);\n    if (available.length === 0) return; \/\/ fully booked\n\n    state.selectedDate = dateStr;\n    state.day = dayKey;\n\n    \/\/ Auto-select first available block\n    if (available.length > 0) {\n      state.block = available[0].key;\n    }\n\n    state.extraHours = 0;\n    render();\n  }\n\n  window.calNav = function(dir) {\n    state.calMonth += dir;\n    if (state.calMonth > 11) { state.calMonth = 0; state.calYear++; }\n    if (state.calMonth < 0)  { state.calMonth = 11; state.calYear--; }\n    fetchAvailability(state.calYear, state.calMonth);\n    renderCalendar();\n  };\n\n  function renderCalendar() {\n    var grid = document.getElementById(\"calGrid\");\n    var label = document.getElementById(\"calMonthLabel\");\n    label.textContent = MONTH_NAMES[state.calMonth] + \" \" + state.calYear;\n\n    if (state.calLoading) {\n      grid.innerHTML = '<div class=\"cal-loading\" style=\"grid-column:1\/-1\">Loading availability...<\/div>';\n      return;\n    }\n\n    var html = \"\";\n    \/\/ Day headers\n    DAY_NAMES.forEach(function(d) {\n      html += '<div class=\"cal-header\">' + d + '<\/div>';\n    });\n\n    var firstDay = new Date(state.calYear, state.calMonth, 1).getDay();\n    var daysInMonth = new Date(state.calYear, state.calMonth + 1, 0).getDate();\n    var today = new Date();\n    today.setHours(0, 0, 0, 0);\n\n    \/\/ Empty cells before first day\n    for (var i = 0; i < firstDay; i++) {\n      html += '<div class=\"cal-day cal-empty\"><\/div>';\n    }\n\n    for (var d = 1; d <= daysInMonth; d++) {\n      var dateStr = state.calYear + \"-\" + String(state.calMonth + 1).padStart(2, \"0\") + \"-\" + String(d).padStart(2, \"0\");\n      var dateObj = new Date(state.calYear, state.calMonth, d);\n      var isPast = dateObj < today;\n      var isToday = dateObj.getTime() === today.getTime();\n      var isSelected = state.selectedDate === dateStr;\n      var fullyBooked = !isPast && isDateFullyBooked(dateStr);\n      var partiallyBooked = !isPast && !fullyBooked && isDatePartiallyBooked(dateStr);\n\n      var classes = \"cal-day\";\n      if (isPast) classes += \" cal-past\";\n      if (isToday) classes += \" cal-today\";\n      if (isSelected) classes += \" cal-selected\";\n      if (fullyBooked) classes += \" cal-busy-full\";\n      else if (partiallyBooked) classes += \" cal-busy-partial\";\n\n      var dot = \"\";\n      if (!isPast) {\n        if (fullyBooked) dot = '<span class=\"cal-dot dot-busy\"><\/span>';\n        else if (partiallyBooked) dot = '<span class=\"cal-dot dot-partial\"><\/span>';\n        else dot = '<span class=\"cal-dot dot-free\"><\/span>';\n      }\n\n      var onclick = isPast || fullyBooked ? \"\" : ' onclick=\"selectDate(\\'' + dateStr + '\\')\"';\n      html += '<div class=\"' + classes + '\"' + onclick + '>' + d + dot + '<\/div>';\n    }\n\n    grid.innerHTML = html;\n\n    \/\/ Update selected date display\n    var display = document.getElementById(\"selectedDateDisplay\");\n    if (state.selectedDate) {\n      var selDate = new Date(state.selectedDate + \"T12:00:00\");\n      var dayName = [\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"][selDate.getDay()];\n      var monthName = MONTH_NAMES[selDate.getMonth()];\n      display.textContent = dayName + \", \" + monthName + \" \" + selDate.getDate() + \", \" + selDate.getFullYear();\n    } else {\n      display.textContent = \"Select a date to see pricing\";\n    }\n  }\n\n  window.selectDate = selectDate;\n\n  \/\/ Override renderDayBlock to work with calendar selection\n  function renderDayBlock() {\n    \/\/ Day selector is now hidden \u2014 driven by calendar\n    var dayContainer = document.getElementById(\"daySelector\");\n    dayContainer.style.display = \"none\";\n\n    \/\/ Block buttons \u2014 only show available blocks for selected date\n    var blockContainer = document.getElementById(\"blockSelector\");\n    var hint = document.getElementById(\"blockHint\");\n\n    if (!state.selectedDate) {\n      blockContainer.innerHTML = \"\";\n      hint.textContent = \"\";\n      return;\n    }\n\n    var blocks = BLOCK_OPTIONS[state.day] || [];\n    var available = getAvailableBlocks(state.selectedDate);\n    var availableKeys = available.map(function(b) { return b.key; });\n\n    if (blocks.length <= 1) {\n      blockContainer.innerHTML = \"\";\n      var blk = activeBlock();\n      hint.textContent = state.day === \"weekday\"\n        ? \"Weekday events include \" + blk.hours + \" hours with flexible start time \u00b7 $\" + blk.price\n        : blk.sublabel + \" \u00b7 $\" + blk.price;\n    } else {\n      blockContainer.innerHTML = \"\";\n      blocks.forEach(function(opt) {\n        var isAvailable = availableKeys.includes(opt.key);\n        var btn = document.createElement(\"button\");\n        btn.className = \"block-btn\" + (state.block === opt.key ? \" selected\" : \"\");\n        if (!isAvailable) {\n          btn.style.opacity = \"0.4\";\n          btn.style.cursor = \"not-allowed\";\n          btn.style.textDecoration = \"line-through\";\n        }\n        btn.innerHTML = '<div class=\"block-label\">' + opt.label + '<\/div>' +\n          '<div class=\"block-price\">' + opt.sublabel + ' \u00b7 $' + opt.price +\n          (!isAvailable ? ' \u00b7 Booked' : '') + '<\/div>';\n        btn.onclick = function() {\n          if (!isAvailable) return;\n          state.block = opt.key;\n          state.extraHours = 0;\n          render();\n        };\n        blockContainer.appendChild(btn);\n      });\n      hint.textContent = \"\";\n    }\n\n    \/\/ Update extra hours description\n    var extraDesc = document.getElementById(\"extraHoursDesc\");\n    if (extraDesc) {\n      if (state.block === \"fullday\") {\n        extraDesc.textContent = \"Full day already included \u2014 no extra hours needed\";\n      } else {\n        var blk = activeBlock();\n        extraDesc.textContent = \"$\" + EXTRA_HOUR_RATE + \" per additional hour beyond \" + blk.hours + \"h\";\n      }\n    }\n  }\n\n  \/\/ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n  \/\/ \u2551  INIT                                            \u2551\n  \/\/ \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n  document.getElementById(\"guestSlider\").addEventListener(\"input\", function() {\n    state.guests = parseInt(this.value);\n    render();\n  });\n\n  \/\/ Fetch initial month's availability\n  fetchAvailability(state.calYear, state.calMonth);\n\n  \/\/ Also prefetch next month\n  var nextMonth = state.calMonth + 1;\n  var nextYear = state.calYear;\n  if (nextMonth > 11) { nextMonth = 0; nextYear++; }\n  fetchAvailability(nextYear, nextMonth);\n\n  render();\n})();\n<\/script>\n<\/body>\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Montreal Event space A Space That Shapes Itself Around Your Gathering Luma Lofts is a natural-light event space in Montreal perfect for intimate gatherings, workshops, and small celebrations. It accommodates&#8230;<\/p>","protected":false},"author":1,"featured_media":0,"parent":3118,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-10109","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.9 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Event Venue: Explore Luma Lofts for Small Events - Luma Lofts<\/title>\n<meta name=\"description\" content=\"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/lumalofts.ca\/fr\/weddings\/event-venues-workshops\/\" \/>\n<meta property=\"og:locale\" content=\"fr_CA\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Event Venues &amp; Workshops\" \/>\n<meta property=\"og:description\" content=\"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/lumalofts.ca\/fr\/weddings\/event-venues-workshops\/\" \/>\n<meta property=\"og:site_name\" content=\"Luma Lofts\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/lumaloft\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-24T15:32:35+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Estimation du temps de lecture\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/\",\"url\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/\",\"name\":\"Event Venue: Explore Luma Lofts for Small Events - Luma Lofts\",\"isPartOf\":{\"@id\":\"https:\/\/lumalofts.ca\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg\",\"datePublished\":\"2025-08-20T14:15:49+00:00\",\"dateModified\":\"2026-02-24T15:32:35+00:00\",\"description\":\"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.\",\"breadcrumb\":{\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#breadcrumb\"},\"inLanguage\":\"fr-CA\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-CA\",\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage\",\"url\":\"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg\",\"contentUrl\":\"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/lumalofts.ca\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Weddings\",\"item\":\"https:\/\/lumalofts.ca\/weddings\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Event Venues &amp; Workshops\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/lumalofts.ca\/#website\",\"url\":\"https:\/\/lumalofts.ca\/\",\"name\":\"Luma Lofts \u2013 Creative Studio Space in Montreal\",\"description\":\"Creative Studio Space in Montreal\",\"publisher\":{\"@id\":\"https:\/\/lumalofts.ca\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/lumalofts.ca\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-CA\"},{\"@type\":[\"Organization\",\"Place\"],\"@id\":\"https:\/\/lumalofts.ca\/#organization\",\"name\":\"Luma Lofts\",\"url\":\"https:\/\/lumalofts.ca\/\",\"logo\":{\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo\"},\"image\":{\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo\"},\"sameAs\":[\"https:\/\/www.facebook.com\/lumaloft\/\",\"https:\/\/www.instagram.com\/lumalofts\/\"],\"telephone\":[],\"openingHoursSpecification\":[{\"@type\":\"OpeningHoursSpecification\",\"dayOfWeek\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"],\"opens\":\"09:00\",\"closes\":\"17:00\"}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-CA\",\"@id\":\"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo\",\"url\":\"https:\/\/lumalofts.ca\/wp-content\/uploads\/cropped-LUMA-logo.png\",\"contentUrl\":\"https:\/\/lumalofts.ca\/wp-content\/uploads\/cropped-LUMA-logo.png\",\"width\":512,\"height\":512,\"caption\":\"Luma Lofts\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Event Venue: Explore Luma Lofts for Small Events - Luma Lofts","description":"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/lumalofts.ca\/fr\/weddings\/event-venues-workshops\/","og_locale":"fr_CA","og_type":"article","og_title":"Event Venues &amp; Workshops","og_description":"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.","og_url":"https:\/\/lumalofts.ca\/fr\/weddings\/event-venues-workshops\/","og_site_name":"Luma Lofts","article_publisher":"https:\/\/www.facebook.com\/lumaloft\/","article_modified_time":"2026-02-24T15:32:35+00:00","og_image":[{"url":"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Estimation du temps de lecture":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/","url":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/","name":"Event Venue: Explore Luma Lofts for Small Events - Luma Lofts","isPartOf":{"@id":"https:\/\/lumalofts.ca\/#website"},"primaryImageOfPage":{"@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage"},"image":{"@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage"},"thumbnailUrl":"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg","datePublished":"2025-08-20T14:15:49+00:00","dateModified":"2026-02-24T15:32:35+00:00","description":"Host your next small celebration at Luma Lofts, the ideal event venue in Montreal for, a wedding ceremony, baby shower and networking events.","breadcrumb":{"@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#breadcrumb"},"inLanguage":"fr-CA","potentialAction":[{"@type":"ReadAction","target":["https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/"]}]},{"@type":"ImageObject","inLanguage":"fr-CA","@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#primaryimage","url":"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg","contentUrl":"https:\/\/lumalofts.ca\/wp-content\/uploads\/DSC01682_websize-782x1043.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lumalofts.ca\/"},{"@type":"ListItem","position":2,"name":"Weddings","item":"https:\/\/lumalofts.ca\/weddings\/"},{"@type":"ListItem","position":3,"name":"Event Venues &amp; Workshops"}]},{"@type":"WebSite","@id":"https:\/\/lumalofts.ca\/#website","url":"https:\/\/lumalofts.ca\/","name":"Luma Lofts \u2013 Creative Studio Space in Montreal","description":"Creative Studio Space in Montreal","publisher":{"@id":"https:\/\/lumalofts.ca\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lumalofts.ca\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fr-CA"},{"@type":["Organization","Place"],"@id":"https:\/\/lumalofts.ca\/#organization","name":"Luma Lofts","url":"https:\/\/lumalofts.ca\/","logo":{"@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo"},"image":{"@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo"},"sameAs":["https:\/\/www.facebook.com\/lumaloft\/","https:\/\/www.instagram.com\/lumalofts\/"],"telephone":[],"openingHoursSpecification":[{"@type":"OpeningHoursSpecification","dayOfWeek":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"opens":"09:00","closes":"17:00"}]},{"@type":"ImageObject","inLanguage":"fr-CA","@id":"https:\/\/lumalofts.ca\/weddings\/event-venues-workshops\/#local-main-organization-logo","url":"https:\/\/lumalofts.ca\/wp-content\/uploads\/cropped-LUMA-logo.png","contentUrl":"https:\/\/lumalofts.ca\/wp-content\/uploads\/cropped-LUMA-logo.png","width":512,"height":512,"caption":"Luma Lofts"}]}},"_links":{"self":[{"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/pages\/10109","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/comments?post=10109"}],"version-history":[{"count":87,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/pages\/10109\/revisions"}],"predecessor-version":[{"id":10389,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/pages\/10109\/revisions\/10389"}],"up":[{"embeddable":true,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/pages\/3118"}],"wp:attachment":[{"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/media?parent=10109"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/categories?post=10109"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lumalofts.ca\/fr\/wp-json\/wp\/v2\/tags?post=10109"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}