1<!DOCTYPE html> 2<html lang="en" data-ver="1404"> 3<head>
3<script>(function(w,i,g){w[g]=w[g]||[];if(typeof w[g].push=='function')w[g].push(i)}) 4(window,'GTM-MS2KK66X','google_tags_first_party');</script>
4<script>(function(w,d,s,l){w[l]=w[l]||[];(function(){w[l].push(arguments);})('set', 'developer_id.dY2E1Nz', true); 5 var f=d.getElementsByTagName(s)[0], 6 j=d.createElement(s);j.async=true;j.src='/ulg8/'; 7 f.parentNode.insertBefore(j,f); 8 })(window,document,'script','dataLayer');</script>
8 9 <meta charset="utf-8"> 10 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 11 <meta name="thumbnail" content="https://os-data-2.s3-ap-southeast-2.amazonaws.com/poa-com-au/images/fbshare.jpg" /> 12 <title>POA | Billboard Advertising</title><link rel="shortcut icon" href="/favicon.png" type="image/png" /><meta name="description" content="POA is one of the largest and fastest growing regional advertising organisations in Australia, we bring billboards and digital signage solutions to Cairns, Townsville, Toowoomba and Brisbane." /> 13<meta itemprop="name" content=" POA is one of the largest and fastest growing regional advertising organisations in Australia, we bring billboards and digital signage solutions to Cairns, Townsville, Toowoomba and Brisbane. | POA Outdoor Advertising" /> 14<meta property="og:description" content="POA is one of the largest and fastest growing regional advertising organisations in Australia, we bring billboards and digital signage solutions to Cairns, Townsville, Toowoomba and Brisbane." /> 15<meta itemprop="name" content=" POA | Billboard Advertising | POA Outdoor Advertising" /> 16<meta property="og:title" content=" POA | Billboard Advertising | POA Outdoor Advertising" /> 17<meta property="og:url" content="https://www.poa.com.au/" /> 18<meta property="og:site_name" content=" POA | Billboard Advertising | POA Outdoor Advertising" /> 19<meta property="og:type" content="website"/> 20<link rel="canonical" href="https://www.poa.com.au/" /> 21<meta property="fb:admins" content="100003191299389"/> 22<meta property="fb:page_id" content="107330822636013"/> 23<meta itemprop="image" content="https://cdn.xargocdn.com/poa-com-au/d2568c89-cd57-4b51-94d6-b5ff7fb2adf2/ShareImage_original.webp" /> 24<meta property="og:image" content="https://cdn.xargocdn.com/poa-com-au/d2568c89-cd57-4b51-94d6-b5ff7fb2adf2/ShareImage_original.webp" /> 25<meta name="twitter:image" content="https://cdn.xargocdn.com/poa-com-au/d2568c89-cd57-4b51-94d6-b5ff7fb2adf2/ShareImage_original.webp" /> 26<meta name="robots" content="NOODP" /> 27 28 <link href="/templates/oracle/css/home-min.css?ver=1404" rel="stylesheet" type="text/css" /> 29<!-- Google Tag Manager --> 30
30<script nonce="WWpGbVlXTTBZVFUzWVdJNE16QXk=">
vendor: 338 bytes, lines 30-35
30 31 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 32 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 33 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 34 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 35 })(window,document,'script','dataLayer','
35GTM-MS2KK66X
vendor: 6 bytes, lines 35-36
35'); 36
36</script>
36 37<!-- End Google Tag Manager --> 38</head> 39<body class=" page-2 template-homepage" data-id="2" data-template="oracle"> 40<!-- Google Tag Manager (noscript) --> 41<noscript><iframe src=https://www.googletagmanager.com/ns.html?id=GTM-MS2KK66X 42height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 43<!-- End Google Tag Manager (noscript) --> <a class="skip-to-content" href="#page-content">Skip to main content</a> 44 <div class="section-countdown"> 45 <div class="wrapper"> 46 <div class="title"> 47 <span> 48 We have some<br /> 49 <span>Big News</span> <span>Coming...</span> 50 </span> 51 </div> 52 <div class="countdown"> 53 <div class="box"> 54 <span>0-329</span> 55 <span>Days<br />To Go</span> 56 </div> 57 <div class="img"> 58 <img loading="lazy" src="/templates/oracle/img/countdown.webp" alt="Big news countdown" /> 59 </div> 60 </div> 61 </div> 62 </div> 63 64 <header class="contrast-inverted header--v10"> 65 <div class="header--v10-bg"> 66 <img src="/templates/oracle/img/header--v10-bg.webp" alt="Header background" /> 67 </div> 68 <div class="header--v10-top"> 69 <div class="wrapper"> 70 <a href="https://www.poa.com.au/" class="header--v10-logo"> 71 <img src="/templates/oracle/img/header--v10-logo-mobile.svg?ver=123" alt="Header logo Mobile" /> 72 <img src="/templates/oracle/img/header--v10-logo.svg" alt="Header logo" /> 73 </a> 74 </div> 75 <div class="header--v10-neon"> 76 <img src="https://www.poa.com.au/templates/oracle/img/header--v10-neon.webp" alt="Header neon" /> 77 <a class="header-v10__neon-text" href="https://www.poa.com.au/join-our-crew/" > 78 79 <span class="item-title">Love Sales? </span> 80 <span class="item-subtitle">Apply Here</span> 81 82 </a> 83 </div> 84 </div> 85 <div class="header--v10-bottom"> 86 <div class="wrapper"> 87 <nav class="header-nav header--v10-nav" role="navigation" aria-label="Main menu" id="header-nav"> 88 <ul role="menu" aria-hidden="false" class="reset menu-level-1"> 89 <li role="menuitem" aria-haspopup="true" class="is-category menu-457 has-drop "> 90 <button class="drop-control" role="button" aria-label="Toggle dropdown menu"></button> <a aria-haspopup="true" aria-expanded="false" href="javascript:void(0);" title="Our World">Our World</a> 91<ul role="menu" aria-hidden="false" class="reset menu-level-2"> 92 <li role="menuitem" aria-haspopup="true" class="is-page menu-32 "> 93 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/our-story/" title="How We Got Here">How We Got Here</a> 94 </li> 95 <li role="menuitem" aria-haspopup="true" class="is-page menu-360 "> 96 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/leadership-team/" title="At The Helm">At The Helm</a> 97 </li> 98 <li role="menuitem" aria-haspopup="true" class="is-page menu-64 "> 99 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/why-poa/" title="The POA Difference">The POA Difference</a> 100 </li> 101 <li role="menuitem" aria-haspopup="true" class="is-page menu-356 "> 102 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/why-billboards/" title="Impossible to Ignore">Impossible to Ignore</a> 103 </li> 104 <li role="menuitem" aria-haspopup="true" class="is-page menu-6 "> 105 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/faq-s/" title="Got Questions?">Got Questions?</a> 106 </li> 107 <li role="menuitem" aria-haspopup="true" class="is-page menu-36 "> 108 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/charity/" title=" Doing Good"> Doing Good</a> 109 </li> 110 <li role="menuitem" aria-haspopup="true" class="is-page menu-460 "> 111 <a aria-haspopup="true" aria-expanded="false" href="/about-poa/sustainability/" title="Building a Better Backyard">Building a Better Backyard</a> 112 </li> 113</ul> 114 </li> 115 <li role="menuitem" aria-haspopup="true" class="is-category menu-458 has-drop "> 116 <button class="drop-control" role="button" aria-label="Toggle dropdown menu"></button> <a aria-haspopup="true" aria-expanded="false" href="javascript:void(0);" title="The Goods">The Goods</a> 117<ul role="menu" aria-hidden="false" class="reset menu-level-2"> 118 <li role="menuitem" aria-haspopup="true" class="is-link menu-136 ">
119 <a aria-haspopup="true" aria-expanded="false" class="menu-136 Standard" href="https://billboards.poa.com.au/billboards.php" title="" >Locations</a> 120 </li> 121 <li role="menuitem" aria-haspopup="true" class="is-page menu-23 "> 122 <a aria-haspopup="true" aria-expanded="false" href="/billboards/digital-billboards/" title="Digital Billboards">Digital Billboards</a> 123 </li> 124 <li role="menuitem" aria-haspopup="true" class="is-page menu-29 "> 125 <a aria-haspopup="true" aria-expanded="false" href="/billboards/classic-highway-billboards/" title="Classic Highway Billboards">Classic Highway Billboards</a> 126 </li> 127 <li role="menuitem" aria-haspopup="true" class="is-page menu-30 "> 128 <a aria-haspopup="true" aria-expanded="false" href="/billboards/classic-inner-city-billboards/" title="Classic Inner City Billboards">Classic Inner City Billboards</a> 129 </li> 130 <li role="menuitem" aria-haspopup="true" class="is-page menu-31 "> 131 <a aria-haspopup="true" aria-expanded="false" href="/billboards/airport-billboards/" title="Airport Billboards">Airport Billboards</a> 132 </li> 133</ul> 134 </li> 135 <li role="menuitem" aria-haspopup="true" class="is-category menu-459 has-drop "> 136 <button class="drop-control" role="button" aria-label="Toggle dropdown menu"></button> <a aria-haspopup="true" aria-expanded="false" href="javascript:void(0);" title="Extras">Extras</a> 137<ul role="menu" aria-hidden="false" class="reset menu-level-2"> 138 <li role="menuitem" aria-haspopup="true" class="is-page menu-49 "> 139 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/extensions/" title="Extensions">Extensions</a> 140 </li> 141 <li role="menuitem" aria-haspopup="true" class="is-page menu-60 "> 142 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/billboard-design/" title="Billboard Design">Billboard Design</a> 143 </li> 144 <li role="menuitem" aria-haspopup="true" class="is-page menu-51 "> 145 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/maintenance/" title="Maintenance">Maintenance</a> 146 </li> 147 <li role="menuitem" aria-haspopup="true" class="is-page menu-52 "> 148 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/reflective/" title="Reflective">Reflective</a> 149 </li> 150 <li role="menuitem" aria-haspopup="true" class="is-page menu-53 "> 151 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/skin-production/" title="Skin Production">Skin Production</a> 152 </li> 153 <li role="menuitem" aria-haspopup="true" class="is-page menu-275 "> 154 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/signage/" title="Signage ">Signage </a> 155 </li> 156 <li role="menuitem" aria-haspopup="true" class="is-page menu-45 "> 157 <a aria-haspopup="true" aria-expanded="false" href="/the-extras/get-keep-attention/" title="Get & Keep Attention">Get & Keep Attention</a> 158 </li> 159</ul> 160 </li> 161 <li role="menuitem" aria-haspopup="true" class="is-link menu-152 "> 162 <a aria-haspopup="true" aria-expanded="false" class="menu-152 Standard" href="https://billboards.poa.com.au/builder-1.php" title="" >Simulator</a> 163 </li> 164 <li role="menuitem" aria-haspopup="true" class="is-page menu-597 "> 165 <a aria-haspopup="true" aria-expanded="false" href="/our-crib/" title="Our Crib">Our Crib</a> 166 </li> 167 <li role="menuitem" aria-haspopup="true" class="is-page menu-599 "> 168 <a aria-haspopup="true" aria-expanded="false" href="/join-our-crew/" title="Join Our Crew">Join Our Crew</a> 169 </li> 170 <li role="menuitem" aria-haspopup="true" class="is-page menu-405 "> 171 <a aria-haspopup="true" aria-expanded="false" href="/landowners/" title="Got Land?">Got Land?</a> 172 </li> 173 <li role="menuitem" aria-haspopup="true" class="is-module menu-453 "> 174 <a aria-haspopup="true" aria-expanded="false" href="/news/" title="The Scoop">The Scoop</a> 175 </li> 176 <li role="menuitem" aria-haspopup="true" class="is-page menu-7 "> 177 <a aria-haspopup="true" aria-expanded="false" href="/contact/" title="Let's Chat">Let's Chat</a> 178 </li> 179</ul> 180 </div> 181 </div> 182 </div> 183 <button type="button" title="Menu Button" class="mm-menu-button header-v10__burger" aria-label="Open menu" aria-expanded="false"> 184 <span></span> 185 </button> 186 </header> 187
188 <div id="page-content" class="page-content"> 189<div class="section-hero"> 190 191 <div class="img"> 192 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/dba8997a-7757-4f49-9241-36117235c7d9/poafallback_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/dba8997a-7757-4f49-9241-36117235c7d9/poafallback_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/dba8997a-7757-4f49-9241-36117235c7d9/poafallback_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/dba8997a-7757-4f49-9241-36117235c7d9/poafallback_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/dba8997a-7757-4f49-9241-36117235c7d9/poafallback_1600.webp 1600w" sizes="100vw" alt="POA" /> 193 194 <span>Video Loading</span> 195 <iframe src="https://player.vimeo.com/video/1114748664?autopause=false&muted=1&autoplay=1&loop=1&background=1&app_id=122963" frameborder="0" allow="autoplay; fullscreen" title="POA" data-ready="true"></iframe> 196 197 </div> 198</div> 199 200 201<div class="section-why"> 202 <div class="section-why-v2__bg" aria-hidden="true"> 203 <img src="/templates/oracle/img/section-why-v2-bg.png?ver=" alt="" width="389" height="400" /> 204 </div> 205 <div class="wrapper"> 206 <div class="title waypoint"> 207 <h2><span class="bold">No one reaches 96% <br /></span>of QLD like we do!*</h2> 208<p><span class="extracontent1"><span class="bold">With over 40 years of industry experience,</span> we can help you achieve your goals. Whether you’re looking to capture the Southeast Queensland, the North Queensland market and everywhere in between, our expansive network of more than 2,000 billboards means we have the right piece of sky for you!</span></p> </div> 209 210 <div class="items odometer-items waypoint"> 211 <div class="item" data-count="1"> 212 <span class="item-title h2"> 213 Cut Through 214 215 <br /><span>The Noise:</span> 216 217 </span> 218 <span class="item-stat"><span class="odometer" data-odometer-format="(ddd)" data-odometer="5000">0</span><span class="item-stat-symbol">+</span></span> 219 220 <span class="item-desc-title h8">Advertising messages are exposed to you on an average day</span> 221 222 <p>So it’s important you make a <strong>BIG IMPRESSION</strong>.</p> </div> 223 <div class="item" data-count="2"> 224 <span class="item-title h2"> 225 Reach Your 226 227 <br /><span>Audience:</span> 228 229 </span> 230 <p>You can reach more of your customers with billboard advertising.</p> 231 <span class="item-stat"><span class="odometer" data-odometer-format="(ddd)" data-odometer="74">0</span><span class="item-stat-symbol">%</span></span> 232 233 <span class="item-desc-title h8">of Australians see you daily!</span> 234 </div> 235 <div class="item" data-count="3"> 236 <span class="item-title h2"> 237 Repeat Exposure 238 239 <br /><span>Leads to action:</span> 240 241 </span> 242 <p>In marketing, we say you need a minimum of 8 exposures before your customer will buy; how often do you drive past the same Billboards on your commute?</p> 243 <span class="item-desc-title h8">Out-of-home-advertising can increase your online & in-store traffic by up to</span> 244 <span class="item-stat"><span class="odometer" data-odometer-format="(ddd)" data-odometer="63">0</span><span class="item-stat-symbol">%</span></span> 245 </div> 246 </div> 247 </div> 248</div> 249<div class="section-you"> 250 <div class="wrapper"> 251 <div class="title waypoint"> 252 <h2>You <span>Everywhere</span></h2> 253 </div> 254 <div class="items"> 255 <div class="item waypoint"> 256 <a href="//www.poa.com.au/billboards/digital-billboards/" > 257 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/b4b04c17-beec-46d9-a96f-87384c29d955/homeyou1_original.svg" alt="Digital" /> 258 <span class="item-title h3">Digital</span> 259 </a> 260 </div> 261 <div class="item waypoint"> 262 <a href="//www.poa.com.au/billboards/classic-highway-billboards/" > 263 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/105f0f1c-f83a-45f7-87eb-56b03833e4a7/homehighway_original.svg" alt="Highway" /> 264 <span class="item-title h3">Highway</span> 265 </a> 266 </div> 267 <div class="item waypoint">
268 <a href="//www.poa.com.au/billboards/classic-inner-city-billboards/" > 269 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/fdfc5102-f75b-48fa-8267-4d8074795698/homeyou3_original.svg" alt="Inner City" /> 270 <span class="item-title h3">Inner City</span> 271 </a> 272 </div> 273 <div class="item waypoint"> 274 <a href="//www.poa.com.au/billboards/airport-billboards/" > 275 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/f0fa02ba-d704-4399-92ec-475c1769e129/homeairport_original.svg" alt="Airports" /> 276 <span class="item-title h3">Airports</span> 277 </a> 278 </div> 279 </div> 280 </div> 281</div> 282 283<div class="section-reviews"> 284 <div class="wrapper"> 285 <div class="title waypoint"> 286 <h2><strong>The Proof</strong> is in the Pudding</h2> 287 </div> 288 <div class="feed waypoint"> 289
289<script nonce="WWpGbVlXTTBZVFUzWVdJNE16QXk=" src="https://elfsightcdn.com/platform.js" async></script>
289 290 <div class="elfsight-app-d3840127-7ef9-4855-9467-06674c9293b3" data-elfsight-app-lazy></div> 291 </div> 292 </div> 293</div> 294<div class="section-simulator waypoint"> 295 <div class="swiper" data-swiper-type="home-simulator"> 296 <div class="swiper-wrapper"> 297 <div class="swiper-slide"> 298 <div class="img"> 299 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/4da6ee57-3b14-4b4e-8525-013b4c9b2c0c/POA_ArtSimulatorHomepageImage1.crop_1920x699_0%2C290.preview_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/4da6ee57-3b14-4b4e-8525-013b4c9b2c0c/POA_ArtSimulatorHomepageImage1.crop_1920x699_0%2C290.preview_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/4da6ee57-3b14-4b4e-8525-013b4c9b2c0c/POA_ArtSimulatorHomepageImage1.crop_1920x699_0%2C290.preview_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/4da6ee57-3b14-4b4e-8525-013b4c9b2c0c/POA_ArtSimulatorHomepageImage1.crop_1920x699_0%2C290.preview_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/4da6ee57-3b14-4b4e-8525-013b4c9b2c0c/POA_ArtSimulatorHomepageImage1.crop_1920x699_0%2C290.preview_1600.webp 1600w" sizes="100vw" alt="Try our artwork simulator" /> 300 </div> 301 </div> 302 <div class="swiper-slide"> 303 <div class="img"> 304 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/0a881ad6-adbb-4be2-b5e6-b2f35d86bcde/POA_ArtSimulatorHomepageImage3.crop_1920x699_0%2C290.preview_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/0a881ad6-adbb-4be2-b5e6-b2f35d86bcde/POA_ArtSimulatorHomepageImage3.crop_1920x699_0%2C290.preview_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/0a881ad6-adbb-4be2-b5e6-b2f35d86bcde/POA_ArtSimulatorHomepageImage3.crop_1920x699_0%2C290.preview_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/0a881ad6-adbb-4be2-b5e6-b2f35d86bcde/POA_ArtSimulatorHomepageImage3.crop_1920x699_0%2C290.preview_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/0a881ad6-adbb-4be2-b5e6-b2f35d86bcde/POA_ArtSimulatorHomepageImage3.crop_1920x699_0%2C290.preview_1600.webp 1600w" sizes="100vw" alt="Try our artwork simulator" /> 305 </div> 306 </div> 307 <div class="swiper-slide"> 308 <div class="img"> 309 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/eea0e454-0217-4b92-889c-9c6ed734f3b2/POA_ArtSimulatorHomepageImage4.crop_1920x699_0%2C290.preview_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/eea0e454-0217-4b92-889c-9c6ed734f3b2/POA_ArtSimulatorHomepageImage4.crop_1920x699_0%2C290.preview_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/eea0e454-0217-4b92-889c-9c6ed734f3b2/POA_ArtSimulatorHomepageImage4.crop_1920x699_0%2C290.preview_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/eea0e454-0217-4b92-889c-9c6ed734f3b2/POA_ArtSimulatorHomepageImage4.crop_1920x699_0%2C290.preview_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/eea0e454-0217-4b92-889c-9c6ed734f3b2/POA_ArtSimulatorHomepageImage4.crop_1920x699_0%2C290.preview_1600.webp 1600w" sizes="100vw" alt="Try our artwork simulator" /> 310 </div> 311 </div> 312 <div class="swiper-slide"> 313 <div class="img"> 314 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/93db7bbf-01bb-49da-97a7-c58e883d6cd4/POA_ArtSimulatorHomepageImage5.crop_1920x699_0%2C290.preview_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/93db7bbf-01bb-49da-97a7-c58e883d6cd4/POA_ArtSimulatorHomepageImage5.crop_1920x699_0%2C290.preview_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/93db7bbf-01bb-49da-97a7-c58e883d6cd4/POA_ArtSimulatorHomepageImage5.crop_1920x699_0%2C290.preview_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/93db7bbf-01bb-49da-97a7-c58e883d6cd4/POA_ArtSimulatorHomepageImage5.crop_1920x699_0%2C290.preview_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/93db7bbf-01bb-49da-97a7-c58e883d6cd4/POA_ArtSimulatorHomepageImage5.crop_1920x699_0%2C290.preview_1600.webp 1600w" sizes="100vw" alt="Try our artwork simulator" /> 315 </div> 316 </div> 317 <div class="swiper-slide"> 318 <div class="img"> 319 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/904dab3b-5c6d-4adb-af52-708863f82e0d/POA_ArtSimulatorHomepageImage2.crop_1920x699_0%2C290.preview_1600.webp" srcset="https://cdn.xargocdn.com/poa-com-au/904dab3b-5c6d-4adb-af52-708863f82e
3190d/POA_ArtSimulatorHomepageImage2.crop_1920x699_0%2C290.preview_400.webp 400w, https://cdn.xargocdn.com/poa-com-au/904dab3b-5c6d-4adb-af52-708863f82e0d/POA_ArtSimulatorHomepageImage2.crop_1920x699_0%2C290.preview_800.webp 800w, https://cdn.xargocdn.com/poa-com-au/904dab3b-5c6d-4adb-af52-708863f82e0d/POA_ArtSimulatorHomepageImage2.crop_1920x699_0%2C290.preview_1200.webp 1200w, https://cdn.xargocdn.com/poa-com-au/904dab3b-5c6d-4adb-af52-708863f82e0d/POA_ArtSimulatorHomepageImage2.crop_1920x699_0%2C290.preview_1600.webp 1600w" sizes="100vw" alt="Try our artwork simulator" /> 320 </div> 321 </div> 322 </div> 323 </div> 324 <div class="graphics"> 325 <svg fill="none" height="520" viewBox="0 0 405 520" width="405" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="39123a" gradientUnits="userSpaceOnUse" x1="-117.338" x2="45.8622" y1="264.975" y2="70.1882"><stop offset=".1" stop-color="#004986"/><stop offset=".24" stop-color="#0065a4"/><stop offset=".45" stop-color="#009adb"/></linearGradient><linearGradient id="39123b" gradientUnits="userSpaceOnUse" x1="17.0462" x2="162.901" y1="179.107" y2="263.421"><stop offset=".19" stop-color="#c39200"/><stop offset=".23" stop-color="#ca9800"/><stop offset=".47" stop-color="#f0bd00"/><stop offset=".6" stop-color="#ffcb00"/></linearGradient><linearGradient id="39123c" gradientUnits="userSpaceOnUse" x1="-149.072" x2="54.4365" y1="-.354807" y2="73.8395"><stop offset=".35" stop-color="#ffcb00"/><stop offset=".49" stop-color="#e2b000"/><stop offset=".66" stop-color="#c39200"/></linearGradient><clipPath id="39123d"><path d="m-149-1h553.081v521h-553.081z"/></clipPath><g clip-path="url(#39123d)"><path d="m143.228-1c36.096 0 69.948 6.82862 101.61 20.4142 31.608 13.5676 59.285 32.1894 82.96 55.8118 23.675 23.6402 42.288 51.241 55.893 82.84 13.552 31.615 20.39 65.436 20.39 101.479s-6.838 69.845-20.39 101.479c-13.587 31.562-32.2 59.181-55.893 82.84-23.675 23.64-51.352 42.208-82.96 55.811-31.662 13.568-65.514 20.343-101.61 20.343-36.095 0-69.9651-6.775-101.6631-20.343-31.6621-13.603-59.3036-32.153-82.9245-55.811-23.7107-23.641-42.4315-51.278-56.2343-82.84-13.8391-31.652-20.7851-65.436-20.7851-101.479s6.946-69.864 20.7851-101.479c13.8028-31.581 32.5416-59.1998 56.2343-82.84 23.6209-23.6224 51.2624-42.2263 82.9245-55.8118 31.698-13.58558 65.5681-20.4142 101.6631-20.4142zm0 435.365c23.89 0 46.488-4.535 67.83-13.711 21.359-9.087 39.954-21.49 55.911-37.19 15.921-15.665 28.485-34.215 37.621-55.418 9.136-21.328 13.641-44.18 13.641-68.501 0-24.322-4.505-47.048-13.641-68.125-9.136-21.041-21.718-39.538-37.621-55.418-15.975-15.951-34.552-28.479-55.911-37.6197-21.36-9.1227-43.94-13.6572-67.83-13.6572s-47.2417 4.5345-68.5651 13.6572c-21.3235 9.1407-39.9725 21.6867-55.8933 37.6197-15.93871 15.898-28.48508 34.377-37.6211 55.418-9.154 21.077-13.7311 43.803-13.7311 68.125 0 24.321 4.5591 47.173 13.7311 68.501 9.13602 21.221 21.68239 39.753 37.6211 55.418
32515.9029 15.7 34.5519 28.103 55.8933 37.19 21.3234 9.176 44.1901 13.711 68.5651 13.711z" fill="#000" opacity=".2"/><path d="m-32.403 264.653c-.0538-1.685-.1256-3.352-.1256-5.037 0-24.339 4.5411-47.047 13.713-68.106 9.15404-21.042 21.68247-39.52 37.6033-55.4 15.9028-15.934 34.5518-28.462 55.8573-37.6202 1.077-.4481 2.1539-.8603 3.2308-1.2904-5.1154-4.8392-10.7514-8.7105-16.9797-11.5961-12.0618-5.592-25.4518-8.6926-40.3495-9.4095-14.772-.6632-29.14917-.9858-43.0776-.9858h-18.6491s-.0897.0717-.1256.1255c-23.6927 23.6582-42.4135 51.2415-56.2163 82.8215-13.839 31.598-20.767 65.419-20.767 101.461 0 1.578.09 3.119.108 4.678l44.944.377h40.834z" fill="url(#39123a)"/><path d="m77.8934 97.1995c4.7745 4.5345 9.0822 9.9115 12.8874 16.1665 7.9156 12.976 11.8102 31.903 11.8102 56.905s-3.8946 43.911-11.8102 56.905c-7.8616 12.94-17.8054 22.225-29.8671 27.781-12.0618 5.538-25.6133 8.567-40.6546 9.015-15.0951.484-29.56203.681-43.4366.681h-9.2258c.5923 22.439 5.0616 43.588 13.5874 63.429 1.8128 4.194 3.7872 8.262 5.8693 12.241h19.6901c9.6745 0 20.5696-.376 32.5954-1.021 12.0797-.699 24.4646-2.563 37.2084-5.521 12.7258-3.082 25.2897-8.065 37.5497-14.947 12.295-6.972 23.208-16.686 32.649-29.197 9.477-12.528 17.141-28.479 22.921-47.925 5.851-19.411 8.723-43.23 8.723-71.459 0-28.228-2.872-52.191-8.723-71.8347-1.239-4.2298-2.603-8.2804-4.039-12.1876-7.341-.9141-14.808-1.4338-22.4-1.4338-23.172 0-44.9445 4.1402-65.3346 12.3668z" fill="url(#39123b)"/><path d="m78.809 6.95773c-.9872-.25093-1.9564-.57354-2.9436-.80653-12.7618-3.02897-25.2902-4.87503-37.5314-5.591941-12.2771-.6452233-23.0645-1.075372-32.32622-1.075372h-155.00778v75.706213h107.8198c23.585-23.5327 51.1906-42.1008 82.7809-55.6326 12.0797-5.1976 24.5004-9.3737 37.2263-12.59977z" fill="url(#39123c)"/><path d="m20.5644 76.1937c14.8976.7349 28.3056 3.8355 40.3493 9.4095 6.2284 2.8856 11.8823 6.7569 16.9798 11.5961 20.3901-8.2266 42.1805-12.3668 65.3345-12.3668 7.592 0 15.059.5198 22.4 1.4339-5.205-14.2129-11.613-26.275-19.259-36.0609-9.728-12.4922-20.695-22.2064-32.954-29.1425-11.362-6.4164-22.8854-11.0584-34.6061-14.08741-12.7258 3.20821-25.1286 7.40211-37.2262 12.59981-31.59033 13.5317-59.1959 32.0998-82.7809 55.6326h18.649c13.92843 0 28.3056.3226 43.0776.9857z" fill="#fff"/></g></svg> </div> 326 <div class="text"> 327 <img loading="lazy" src="/templates/oracle/img/try-our-artwork.svg" alt="Try our Artwork Simulator" /> 328 </div> 329</div> 330 331<div class="section-everybody"> 332 <div class="wrapper"> 333 <div class="title waypoint"> 334 <h2>Everybody's <span>Doing It</span></h2> 335 </div> 336 <div class="home-logos-carousel waypoint"> 337 <div class="swiper" data-swiper-type="home-logos"> 338 <div class="swiper-wrapper"> 339 <div class="swiper-slide"> 340 <div class="item"> 341 <div class="img"> 342 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/a4142395-1cae-45c0-8b69-701615445a05/amazonlogo_original.webp" alt="Amazon" /> 343 </div> 344 </div> 345 </div> 346 <div class="swiper-slide"> 347 <div class="item"> 348 <div class="img"> 349 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/5f24dea4-3b92-49f1-baf3-dc9b06ce6566/applesm_original.webp" alt="Apple" /> 350 </div> 351 </div> 352 </div> 353 <div class="swiper-slide"> 354 <div class="item"> 355 <div class="img"> 356 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/db736ef4-f4e9-4e50-9224-9ad203813b9f/logoboq_original.webp" alt="BOQ" /> 357 </div> 358 </div> 359 </div> 360 <div class="swiper-slide"> 361 <div class="item"> 362 <div class="img"> 363 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/3cea6d15-4148-418f-8289-0947d93e04f4/cbalogo_original.webp" alt="CBA" /> 364 </div> 365 </div> 366 </div> 367 <div class="swiper-slide"> 368 <div class="item"> 369 <div class="img"> 370 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/12cdead9-ceaa-49bf-a747-416b28892fbf/cowboys_original.webp" alt="Cowboys" /> 371 </div> 372 </div> 373 </div> 374 <div class="swiper-slide"> 375 <div class="item"> 376 <div class="img"> 377 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/7a9b480f-52c3-4154-9f82-729b7d2e0da3/cqunilogo_400.webp" alt="CQ University" /> 378 </div> 379 </div>
380 </div> 381 <div class="swiper-slide"> 382 <div class="item"> 383 <div class="img"> 384 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/4a44a1a9-4702-4fa4-803a-be713d891e11/EbayWhiteLogo2_original.webp" alt="Ebay" /> 385 </div> 386 </div> 387 </div> 388 <div class="swiper-slide"> 389 <div class="item"> 390 <div class="img"> 391 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/c7a0a875-9c2e-4290-968e-3d193dae2843/ExplorePropertyWhiteLogo_400.webp" alt="Explore Property" /> 392 </div> 393 </div> 394 </div> 395 <div class="swiper-slide"> 396 <div class="item"> 397 <div class="img"> 398 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/885d7e91-7b62-410f-bebb-612c342f8edf/FordWhiteLogo_original.webp" alt="Ford" /> 399 </div> 400 </div> 401 </div> 402 <div class="swiper-slide"> 403 <div class="item"> 404 <div class="img"> 405 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/c0e53db4-b7f2-47a0-bffc-72253efe35ac/gglogo_original.webp" alt="Google" /> 406 </div> 407 </div> 408 </div> 409 <div class="swiper-slide"> 410 <div class="item"> 411 <div class="img"> 412 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/30dfb93b-7eca-45d2-88d3-6dfa2805097c/HarveyNormaWhiteLogo_400.webp" alt="Harvey Norman" /> 413 </div> 414 </div> 415 </div> 416 <div class="swiper-slide"> 417 <div class="item"> 418 <div class="img"> 419 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/3da34926-a432-4259-bf50-bf3339222b58/IkeaWhiteLogo2_original.webp" alt="Ikea" /> 420 </div> 421 </div> 422 </div> 423 <div class="swiper-slide"> 424 <div class="item"> 425 <div class="img"> 426 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/39942804-854f-4e49-869a-0c0ceb43c011/JamesCookWhiteLogo_400.webp" alt="James Cook" /> 427 </div> 428 </div> 429 </div> 430 <div class="swiper-slide"> 431 <div class="item"> 432 <div class="img"> 433 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/506615a4-49b8-4674-9d64-4ce176a7011c/KFCWhiteLogo_original.webp" alt="KFC" /> 434 </div> 435 </div> 436 </div> 437 <div class="swiper-slide"> 438 <div class="item"> 439 <div class="img"> 440 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/552840c8-83ea-419f-9d7f-b52bb8a2c7e7/mcdonalds_400.webp" alt="McDonalds" /> 441 </div> 442 </div> 443 </div> 444 <div class="swiper-slide"> 445 <div class="item"> 446 <div class="img"> 447 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/868f7c30-082c-42c1-9c55-3b4530ff17f9/NetflixWhiteLogo2_original.webp" alt="Netflix" /> 448 </div> 449 </div> 450 </div> 451 <div class="swiper-slide"> 452 <div class="item"> 453 <div class="img"> 454 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/ba0148f1-a5d9-493f-9a0c-370828905a9c/OptusWhiteLogo_original.webp" alt="Optus" /> 455 </div> 456 </div> 457 </div> 458 <div class="swiper-slide"> 459 <div class="item"> 460 <div class="img"> 461 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/42b5cec9-ba27-4046-a19b-e6d93348e09e/PBRWhiteLogo_original.webp" alt="PBR" /> 462 </div> 463 </div> 464 </div> 465 <div class="swiper-slide"> 466 <div class="item"> 467 <div class="img"> 468 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/b2e366f5-b8df-46e3-9140-09ab8b454568/qldgovlogo_original.webp" alt="QLD Gov" /> 469 </div> 470 </div> 471 </div> 472 <div class="swiper-slide"> 473 <div class="item"> 474 <div class="img"> 475 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/a82f548e-9a54-409a-a179-526d4b40191f/StanWhiteLogo2_original.webp" alt="Stan" /> 476 </div> 477 </div> 478 </div> 479 <div class="swiper-slide"> 480 <div class="item"> 481 <div class="img"> 482 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/04c2bc2a-6a10-46bd-9653-2e88bb87f7f8/TikTokWhiteLogo_original.webp" alt="TikTok" /> 483 </div> 484 </div> 485 </div> 486 <div class="swiper-slide"> 487 <div class="item"> 488 <div class="img"> 489 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/3f0206be-9a2d-4b3f-b645-5050e18857a4/cityoftsv_original.webp" alt="TownsvilleCouncil" /> 490 </div> 491 </div>
492 </div> 493 <div class="swiper-slide"> 494 <div class="item"> 495 <div class="img"> 496 <img loading="lazy" src="https://cdn.xargocdn.com/poa-com-au/82e5c267-fb31-4f3f-a710-5616a5452e09/ToyotaWhiteLogo_original.webp" alt="Toyota" /> 497 </div> 498 </div> 499 </div> 500 501 </div> 502 </div> 503 </div> 504 <div class="feed waypoint"> 505
505<script nonce="WWpGbVlXTTBZVFUzWVdJNE16QXk=" src="https://elfsightcdn.com/platform.js" async></script>
505 506 <div class="elfsight-app-285c5af7-9160-44eb-8e81-59cb20b93543" data-elfsight-app-lazy></div> 507 </div> 508 </div> 509</div> 510 511<div class="section-faqs"> 512 <div class="wrapper"> 513 <div class="title"> 514 <h2>Frequently Asked <span>Questions</span></h2> 515 <a href="#footer-form" class="link2">Let's Talk</a> 516 </div> 517 <div class="text"> 518<accordion-holder id="acc-home-faqs" class="hide-on-load"> 519 <div class="accordion"> 520 <accordion-item 521 data-itemid="367" 522 identifier="acc-home-faqs" 523 headline="* How does POA reach 96% of Queensland?" 524 link="" 525 src="" 526 srcset="" 527 target="_self" 528 > 529 <p><span>POA has over 2000 outdoor advertising opportunities throughout Queensland with majority being in regional areas, and more than half of Queensland’s population lives regionally. </span><span>Source: OMA Move* over a 12-month period.</span></p> </accordion-item> 530 <accordion-item 531 data-itemid="347" 532 identifier="acc-home-faqs" 533 headline="What’s The Difference Between Static and Digital Billboards? " 534 link="" 535 src="" 536 srcset="" 537 target="_self" 538 > 539 <p>Static billboards are the traditional option where the artwork is physically installed and displayed. There’s a lot of room for creativity with static billboards - we can create billboard extensions to achieve a pop-out or 3D effect, add reflective material to increase visibility, and use moving components to bring the artwork to life.</p> 540<p>Digital billboards display a rotation of visuals in high definition, running continuously to reach a wider audience. Our digital billboard advertising has a quick turnaround from booking to going live, and unlimited artwork changes at any time during the campaign. Terms and conditions apply.</p> </accordion-item> 541 <accordion-item 542 data-itemid="348" 543 identifier="acc-home-faqs" 544 headline="How Soon Can a Billboard Campaign Go Live After Booking? " 545 link="" 546 src="" 547 srcset="" 548 target="_self" 549 > 550 <p>Our digital billboards can go live within a week of booking.</p> 551<p>Our static billboards require 6 weeks for in-house development of the artwork, production of the skin, and on-site installation. This can be reduced to 3 weeks if the artwork is complete and ready.</p> </accordion-item> 552 <accordion-item 553 data-itemid="349" 554 identifier="acc-home-faqs" 555 headline="How Often Will My Media Be Shown on Digital Billboards? " 556 link="" 557 src="" 558 srcset="" 559 target="_self" 560 > 561 <p>POA’s digital billboards have a standard 10-second display time. We also offer 20 and 25-second display times. Digital billboards in airports and terminals have different display times between 7-15 seconds.</p> </accordion-item> 562 <accordion-item 563 data-itemid="350" 564 identifier="acc-home-faqs" 565 headline="How Often Can I Change the Billboard Artwork? " 566 link="" 567 src="" 568 srcset="" 569 target="_self" 570 > 571 <p>The artwork for a digital billboard can be changed hourly, daily, or weekly, with no limit on the number of changes. Use our online artwork simulator to preview how your media will look on the digital billboard.</p> 572<p>Artwork for static billboards has a longer turnaround time - most clients refresh the artwork every 6-12 months.</p> </accordion-item> 573 <accordion-item 574 data-itemid="351" 575 identifier="acc-home-faqs" 576 headline="Can Digital Billboards Display Animated Visuals? " 577 link="" 578 src="" 579 srcset="" 580 target="_self" 581 > 582 <p>Our digital billboards in airports and terminals can display animated visuals. Animated visuals for roadside digital billboards are not permitted.</p> </accordion-item> 583 <accordion-item 584 data-itemid="352" 585 identifier="acc-home-faqs" 586 headline="How Long Do I Need to Book the Billboards for? " 587 link="" 588 src="" 589 srcset="" 590 target="_self" 591 > 592 <p>There is no minimum or maximum duration for booking billboard advertising. Static billboards are booked in 4-week blocks and most advertisements are booked for one to three years. Digital billboards can be booked in weekly intervals as no physical installation is required.</p> </accordion-item> 593 <accordion-item 594 data-itemid="353" 595 identifier="acc-home-faqs" 596 headline="Can You Help Design the Billboard Artwork?" 597 link="" 598 src="" 599 srcset="" 600 target="_self" 601 > 602 <p>Yes. POA has an in-house team of graphic designers who can work with you to create visually stunning billboard media that resonates with your audience. We also work with award-winning copywriters to craft memorable messaging that aligns with your brand. The Queensland Multi Media Awards have awarded our billboard designs for creativity and a high standard of quality.</p> </accordion-item> 603 <accordion-item 604 data-itemid="354" 605 identifier="acc-home-faqs" 606 headline="How Often Will the Billboard Be Maintained? " 607 link="" 608 src="" 609 srcset="" 610 target="_self" 611 > 612 <p>Our static billboards are inspected twice a year to ensure high visibility and quality. We monitor our billboards and arrange professional cleaning to remove dirt and mildew from the canvas. We also mow and maintain the grass and other vegetation around the sign structures to ensure full visibility.</p> </accordion-item> 613 <accordion-item 614 data-itemid="355" 615 identifier="acc-home-faqs" 616 headline="How Is the Performance of the Digital Billboards Measured? " 617 link="" 618 src="" 619 srcset="" 620 target="_self" 621 > 622 <p>We use Broadsign for digital scheduling, to provide proof of play and performance reports. We are planning to deliver more performance metrics in the near future.</p> 623<p>Businesses can track the performance of billboards by benchmarking the traffic of their website (or other target destination, like a specific store branch) at the start of the campaign. As the billboard campaign goe
623s on, businesses can attribute the increase in traffic, revenue, or online searches to billboard advertising, providing a real-time view of performance.</p> 624<p>There are also less measurable benefits, such as brand recognition and perception, that still have a tangible impact on the business.</p> </accordion-item> 625 </div> 626</accordion-holder> 627 </div> 628 </div> 629</div> 630 631 632 633 <footer class="contrast-inverted footer--v2" role="contentinfo"> 634 <div class="footer-v2__bg" aria-hidden="true"></div> 635 <div class="wrapper"> 636 <div class="footer-info"> 637 <span class="item-title h2">Find <span>Us</span></span> 638 <a class="item-phone h2" href="tel:0747584600">07 4758 4600</a> 639 <div class="item-addresses"> 640 <p>221 Sturt Street<br /> Townsville, QLD 4810</p> 641<p>PO BOX 1754, TOWNSVILLE, QLD 4810</p> </div> 642 <div class="footer-copyright footer-copyright--lg"> 643 <p> 644 © 2026 POA 645 <span>|</span> <a href="/sitemap/">Sitemap</a> 646 <span>|</span> <a href="/privacy-policy/">Privacy Policy</a> 647 </p> 648 <p>Site by <a aria-label="OracleStudio" target="_blank" rel="noopener noreferrer" href="https://www.oraclestudio.com.au">OracleStudio</a> <span>|</span> 649 Design by <a aria-label="Novellus" target="_blank" rel="noopener noreferrer" href="javascript:;">Novellus</a></p> 650 </div> 651 </div> 652 <div class="footer-social"> 653 <span class="item-title h2">Let's Get <br /><span>Social</span></span> 654 <ul class="reset"> 655 <li> 656 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.facebook.com/POABillboards/" aria-label="Facebook"> 657 <svg fill="none" height="19" viewBox="0 0 10 19" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m9.18359 10.375h-2.63671v7.875h-3.51563v-7.875h-2.882812v-3.23438h2.882812v-2.49609c0-2.8125 1.6875-4.39453 4.25391-4.39453 1.23046 0 2.53125.246094 2.53125.246094v2.777346h-1.44141c-1.40625 0-1.82812.84375-1.82812 1.75781v2.10937h3.1289z" fill="#001d3c"/></svg> <span>Facebook</span> 658 </a> 659 </li> 660 <li> 661 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.instagram.com/poa_billboards/" aria-label="Instagram"> 662 <svg fill="none" height="17" viewBox="0 0 16 17" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 4.20703c2.2148 0 4.043 1.82813 4.043 4.04297 0 2.25-1.8282 4.043-4.043 4.043-2.25 0-4.04297-1.793-4.04297-4.043 0-2.21484 1.79297-4.04297 4.04297-4.04297zm0 6.67967c1.44141 0 2.6016-1.16014 2.6016-2.6367 0-1.44141-1.16019-2.60156-2.6016-2.60156-1.47656 0-2.63672 1.16015-2.63672 2.60156 0 1.47656 1.19531 2.6367 2.63672 2.6367zm5.1328-6.82029c0-.52735-.4219-.94922-.9492-.94922-.5274 0-.9492.42187-.9492.94922 0 .52734.4218.94921.9492.94921.5273 0 .9492-.42187.9492-.94921zm2.6719.94921c.0703 1.30079.0703 5.20318 0 6.50388-.0703 1.2657-.3516 2.3555-1.2656 3.3047-.9141.9141-2.0391 1.1953-3.3047 1.2656-1.30081.0704-5.20315.0704-6.50393 0-1.26563-.0703-2.35547-.3515-3.30469-1.2656-.914061-.9492-1.195311-2.039-1.265624-3.3047-.0703122-1.3007-.0703122-5.20309 0-6.50388.070313-1.26562.351563-2.39062 1.265624-3.30468.94922-.914065 2.03906-1.195315 3.30469-1.265628 1.30078-.070312 5.20312-.070312 6.50393 0 1.2656.070313 2.3906.351563 3.3047 1.265628.914.91406 1.1953 2.03906 1.2656 3.30468zm-1.6875 7.87498c.4219-1.0195.3164-3.48044.3164-4.6406 0-1.125.1055-3.58594-.3164-4.64062-.2813-.66797-.8086-1.23047-1.4766-1.47657-1.0547-.42187-3.5156-.3164-4.6406-.3164-1.16016 0-3.62109-.10547-4.64062.3164-.70313.28125-1.23047.8086-1.51172 1.47657-.42188 1.05468-.31641 3.51562-.31641 4.64062 0 1.16016-.10547 3.6211.31641 4.6406.28125.7032.80859 1.2305 1.51172 1.5117 1.01953.4219 3.48046.3165 4.64062.3165 1.125 0 3.5859.1054 4.6406-.3165.668-.2812 1.2305-.8085 1.4766-1.5117z" fill="#001d3c"/></svg> <span>Instagram</span> 663 </a> 664 </li> 665 <li> 666 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.linkedin.com/company/poabillboards" aria-label="LinkedIn"> 667 <svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg"> 668<path fill-rule="evenodd" clip-rule="evenodd" d="M0.182196 13.655H3.25363V4.4415H0.182196V13.655ZM1.71748 3.18394C2.78821 3.18394 3.45568 2.47554 3.45568 1.59154C3.43582 0.687744 2.78821 0 1.73734 0C0.686474 0 0 0.686884 0 1.59068C0 2.47554 0.666614 3.18308 1.69848 3.18308H1.71748V3.18394ZM14.3322 13.655V8.37258C14.3322 5.54241 12.8168 4.22545 10.7953 4.22545C9.16421 4.22545 8.4337 5.11978 8.02699 5.74727V4.4415H4.9547C4.99528 5.30656 4.9547 13.655 4.9547 13.655H8.02699V8.50944C8.02699 8.23486 8.04685 7.95942 8.12802 7.76316C8.34994 7.21314 8.85508 6.64332 9.70389 6.64332C10.8161 6.64332 11.2608 7.48772 11.2608 8.72635V13.6559L14.3322 13.655Z" fill="#003B4A"/> 669</svg> 670 <span>LinkedIn</span> 671 </a> 672 </li> 673 </ul>
674 </div> 675 <div class="footer-form" id="footer-form"> 676 <span class="item-title h2">Let's <span>Talk Now</span></span> 677 <link href="https://assets.xargocdn.com/surveyjs/v2/survey-core.min.css" type="text/css" rel="stylesheet"> 678<link href="/templates/oracle/css/surveyjs-min.css?ver=1404" type="text/css" rel="stylesheet">
679<script type="text/javascript" src="https://assets.xargocdn.com/surveyjs/v2/survey.core.min.js"></script>
vendor: 1 bytes, line 679
679
680<script type="text/javascript" src="https://assets.xargocdn.com/surveyjs/v2/survey-js-ui.min.js"></script>
vendor: 1 bytes, line 680
680
681<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" defer></script>
vendor: 1 bytes, line 681
681
682<script> 683(function() { 684 if (window.SurveyJsTurnstile) return; 685 686 window.SurveyJsTurnstile = { 687 tokens: {}, 688 689 setToken: function(formId, token) { 690 this.tokens[formId] = token || ''; 691 }, 692 693 getToken: function(formId) { 694 return this.tokens[formId] || ''; 695 }, 696 697 clearToken: function(formId) { 698 this.tokens[formId] = ''; 699 }, 700 701 readTokenFromDom: function(formId) { 702 var input = document.querySelector( 703 '#turnstile-container-' + formId + ' input[name="cf-turnstile-response"]' 704 ); 705 return (input && input.value) ? input.value : ''; 706 }, 707 708 getTokenForSubmit: function(formId) { 709 var token = this.getToken(formId); 710 if (!token) token = this.readTokenFromDom(formId); 711 if (token) this.setToken(formId, token); 712 return token; 713 }, 714 715 isContainerVisible: function(formId) { 716 var container = document.querySelector('#turnstile-container-' + formId); 717 if (!container) return false; 718 719 // Open Fancybox modals are visible even before Turnstile renders (empty container = 0 height). 720 if (container.closest('.fancybox__container:not([aria-hidden="true"])')) { 721 return true; 722 } 723 724 var el = container; 725 while (el) { 726 var style = window.getComputedStyle(el); 727 if (style.display === 'none' || style.visibility === 'hidden') { 728 return false; 729 } 730 el = el.parentElement; 731 } 732 733 return container.offsetParent !== null; 734 }, 735 736 hasLiveWidget: function(formId) { 737 var container = document.querySelector('#turnstile-container-' + formId); 738 return !!(container && container.querySelector('iframe[src*="challenges.cloudflare.com"]')); 739 }, 740 741 getSurveyModel: function(formId) { 742 return window['survey' + formId] || null; 743 }, 744 745 rerenderWidget: function(formId, survey) { 746 if (typeof turnstile === 'undefined') return;
747 survey = survey || this.getSurveyModel(formId); 748 var container = document.querySelector('#turnstile-container-' + formId); 749 if (!container) return; 750 var turnstileElement = container.querySelector('.cf-turnstile-surveyjs'); 751 if (!turnstileElement) return; 752 753 this.clearToken(formId); 754 this.clearError(formId); 755 756 container.querySelectorAll('iframe').forEach(function(iframe) { 757 iframe.remove(); 758 }); 759 turnstileElement.innerHTML = ''; 760 761 var self = this; 762 turnstile.render(turnstileElement, { 763 sitekey: turnstileElement.getAttribute('data-sitekey'), 764 appearance: turnstileElement.getAttribute('data-appearance') || 'always', 765 theme: turnstileElement.getAttribute('data-theme') || 'light', 766 callback: function(token) { 767 self.setToken(formId, token); 768 self.clearError(formId); 769 if (survey) self.syncCompleteButton(survey, formId); 770 }, 771 'expired-callback': function() { 772 self.clearToken(formId); 773 if (survey) self.syncCompleteButton(survey, formId); 774 }, 775 'error-callback': function() { 776 self.clearToken(formId); 777 if (survey) self.syncCompleteButton(survey, formId); 778 } 779 }); 780 781 if (survey) this.syncCompleteButton(survey, formId); 782 }, 783 784 refreshVisibleWidgets: function(rootEl) { 785 rootEl = rootEl || document; 786 var self = this; 787 rootEl.querySelectorAll('[id^="turnstile-container-"]').forEach(function(container) { 788 var formId = container.getAttribute('data-form-id') || 789 container.id.replace('turnstile-container-', ''); 790 if (!formId || !self.isContainerVisible(formId)) return; 791 792 var survey = self.getSurveyModel(formId); 793 var hasToken = !!self.getTokenForSubmit(formId); 794 if (!self.hasLiveWidget(formId) || !hasToken) { 795 self.rerenderWidget(formId, survey); 796 } else if (survey) { 797 self.syncCompleteButton(survey, formId); 798 } 799 }); 800 }, 801 802 resetWidget: function(formId) { 803 if (typeof turnstile === 'undefined') return; 804 this.clearToken(formId); 805 var survey = this.getSurveyModel(formId); 806 if (this.hasLiveWidget(formId)) { 807 var el = document.querySelector('#turnstile-container-' + formId + ' .cf-turnstile-surveyjs'); 808 try { 809 if (el) turnstile.reset(el); 810 } catch (e) { 811 this.rerenderWidget(formId, survey); 812 } 813 } else { 814 this.rerenderWidget(formId, survey); 815 } 816 if (survey) this.syncCompleteButton(survey, formId); 817 }, 818 819 syncCompleteButton: function(survey, formId) { 820 var hasToken = !!this.getTokenForSubmit(formId); 821 var surveyContainer = document.getElementById('surveyContainer-' + formId); 822 if (!surveyContainer) return; 823 var btn = surveyContainer.querySelector('.sd-navigation__complete-btn') || 824 surveyContainer.querySelector('.sd-navigation .sd-btn--action'); 825 if (!btn) return; 826 var shouldDisable = survey.isLastPage && !hasToken; 827 btn.disabled = shouldDisable; 828 btn.setAttribute('aria-disabled', shouldDisable ? 'true' : 'false'); 829 btn.classList.toggle('turnstile-complete--waiting', shouldDisable); 830 }, 831 832 showError: function(formId, message) { 833 var container = document.querySelector('#turnstile-container-' + formId); 834 if (!container) return; 835 var msg = container.querySelector('.turnstile-error-msg'); 836 if (!msg) { 837 msg = document.createElement('p'); 838 msg.className = 'turnstile-error-msg'; 839 msg.setAttribute('role', 'alert'); 840 msg.style.color = '#b21f03'; 841 msg.style.marginTop = '0.75em'; 842 container.appendChild(msg); 843 } 844 msg.textContent = message; 845 container.scrollIntoView({ behavior: 'smooth', block: 'center' }); 846 }, 847 848 clearError: function(formId) { 849 var msg = document.querySelector('#turnstile-container-' + formId + ' .turnstile-error-msg'); 850 if (msg) msg.remove(); 851 } 852 }; 853 854 function refreshSurveyTurnstileInFancybox(attempt) { 855 attempt = attempt || 0; 856 if (typeof turnstile === 'undefined') { 857 if (attempt < 20) { 858 setTimeout(function() { 859 refreshSurveyTurnstileInFancybox(attempt + 1); 860 }, 100); 861 } 862 return; 863 } 864 if (!window.SurveyJsTurnstile) return; 865 var fancybox = document.querySelector('.fancybox__container:not([aria-hidden="true"])'); 866 if (!fancybox) return; 867 requestAnimationFrame(function() { 868 requestAnimationFrame(function() { 869 SurveyJsTurnstile.refreshVisibleWidgets(fancybox); 870 }); 871 }); 872 } 873 874 if (!window.__surveyjsFancyboxHooked) { 875 window.__surveyjsFancyboxHooked = true; 876 877 document.addEventListener('click', function(event) { 878 if (!event.target.closest('[data-fancybox]')) return; 879 setTimeout(refreshSurveyTurnstileInFancybox, 50); 880 }); 881 882 document.addEventListener('fancybox:reveal', refreshSurveyTurnstileInFancybox); 883 } 884})(); 885</script>
885 886<style> 887 888.success-overlay-17, #success-overlay-17 { 889 display: none !important; 890 opacity: 0 !important; 891 visibility: hidden !important; 892 pointer-events: none !important; 893} 894 895</style> 896<div id="form-17" class="surveyjs-holder" data-load="surveyjs" data-load-css data-load-js data-load-type="force"> 897 <input id="formid-17" type="hidden" value="17" name="formid" /> 898 <input id="pageurl" class="form-page-url" type="hidden" value="/" name="pageurl" /> 899 <input id="paymentElements-17" type="hidden" value="" name="paymentElements" /> 900 <div class="surveyjs-form-shell"> 901 <h3 class="form-title">Get In Touch</h3> 902 <div id="surveyContainer-17"></div> 903 </div>
904<script> 905 906Survey.surveyLocalization.getLocaleStrings("en").filePlaceholder = 907 "Drag and drop a file here or click the button below to select a file to upload."; 908 909 910 911 912 var surveyJSON17 = {"pages":[{"name":"page1","elements":[{"type":"text","name":"question1","title":"First Name","isRequired":true,"placeholder":"First Name"},{"type":"text","name":"question2","startWithNewLine":false,"title":"Surname","isRequired":true,"placeholder":"Surname"},{"type":"text","name":"question3","title":"Company","isRequired":true,"placeholder":"Company"},{"type":"text","name":"question4","startWithNewLine":false,"title":"Job Title","isRequired":true,"placeholder":"Job Title"},{"type":"text","name":"question5","title":"Area Based","isRequired":true,"placeholder":"Area Based"},{"type":"dropdown","name":"question6","title":"What region are you interested in?","choices":[{"value":"item1","text":"Airlie Beach"},{"value":"item2","text":"Augathella"},{"value":"item3","text":"Biloela"},{"value":"item4","text":"Brisbane"},{"value":"item5","text":"Bowen"},{"value":"item6","text":"Cairns"},{"value":"item7","text":"Charters Towers"},{"value":"item8","text":"Chinchilla"},{"value":"item9","text":"Clermont"},{"value":"item10","text":"Dalby"},{"value":"item11","text":"Emerald"},{"value":"item12","text":"Giru"},{"value":"item13","text":"Gladstone"},{"value":"item14","text":"Goondiwindi"},{"value":"item15","text":"Hervey Bay"},{"value":"item16","text":"Hughenden"},{"value":"item17","text":"Hinchinbrook"},{"value":"item18","text":"Innisfail"},{"value":"item19","text":"Julia Creek"},{"value":"item20","text":"Mackay"},{"value":"item21","text":"Maryborough"},{"value":"item22","text":"Miles"},{"value":"item23","text":"Milaa Milaa"},{"value":"item24","text":"Mount Isa"},{"value":"item25","text":"Port Douglas"},{"value":"item26","text":"Richmond"},{"value":"item27","text":"Rockhampton"},{"value":"item28","text":"St George"},{"value":"item29","text":"Tablelands"},{"value":"item30","text":"Toowoomba"},{"value":"item31","text":"Townsville"},{"value":"item32","text":"Tully"},{"value":"item33","text":"Winton"}],"placeholder":"What region are you interested in?"},{"type":"text","name":"question7","title":"Phone Number","isRequired":true,"placeholder":"Phone Number"},{"type":"text","name":"question8","startWithNewLine":false,"title":"Email Address","isRequired":true,"inputType":"email","placeholder":"Email Address"}]},{"name":"page2","elements":[{"type":"comment","name":"question9","title":"Your Message","placeholder":"Your Message"},{"type":"html","name":"turnstile-widget","title":"Security check","html":"<div id='turnstile-container-17' data-form-id='17'><div class='cf-turnstile-surveyjs' data-appearance='interaction-only' data-sitekey='0x4AAAAAAAfn5Ry99YNSWl_B' data-theme='light'><\/div><\/div>"}]}],"completeText":"Send"}; 913 var survey17 = new Survey.Model(surveyJSON17); 914 915 // Signature pad: pen color (canvas API does not support CSS variables) and optional dimensions 916 (function() { 917 var survey = survey17; 918 var root = document.documentElement; 919 var resolved = getComputedStyle(root).getPropertyValue('--colorSecondary').trim(); 920 var sigWidth = 1400; 921 var sigHeight = 300; 922 survey.getAllQuestions().forEach(function(q) { 923 if (q.getType() === 'signaturepad') { 924 if (resolved) q.penColor = resolved; 925 if (sigWidth != null && sigWidth > 0) q.signatureWidth = sigWidth; 926 if (sigHeight != null && sigHeight > 0) q.signatureHeight = sigHeight; 927 } 928 }); 929 })(); 930 931 (function() { 932 var turnstileFormId = '17'; 933 var surveyTurnstile = survey17; 934 var SJT = window.SurveyJsTurnstile; 935 936 survey17.onAfterRenderQuestion.add(function (survey, options) { 937 if (options.question.name === "turnstile-widget") { 938 const formId = turnstileFormId; 939 const hasWidget = SJT.hasLiveWidget(formId); 940 const hasToken = !!SJT.getTokenForSubmit(formId); 941 942 // Only render while visible; hidden modals refresh on Fancybox reveal. 943 if (SJT.isContainerVisible(formId) && (!hasWidget || !hasToken)) { 944 SJT.rerenderWidget(formId, surveyTurnstile); 945 } else { 946 SJT.syncCompleteButton(surveyTurnstile, formId); 947 } 948 } else if (options.question.getType() === "dropdown") {
949 // Replace SurveyJS custom dropdown with native <select> (e.g. for Fancybox compatibility) 950 const question = options.question; 951 const root = options.htmlElement; 952 if (root.querySelector("select.sd-dropdown-native")) return; 953 954 const choices = question.visibleChoices || question.choices || []; 955 const valueKey = question.valuePropertyName || "value"; 956 const textKey = question.textPropertyName || "text"; 957 958 const select = document.createElement("select"); 959 select.setAttribute("aria-label", question.title); 960 select.className = "sd-input sd-dropdown sd-dropdown-native"; 961 962 if ( question.jsonObj.class && question.jsonObj.class === "is-payment-dropdown") { 963 select.classList.add("is-payment-dropdown"); 964 } 965 966 select.id = question.inputId; 967 if (question.isRequired) select.required = true; 968 if (question.readOnly) select.disabled = true; 969 970 const placeholder = question.placeholder || question.optionsCaption || "Select..."; 971 const emptyOption = document.createElement("option"); 972 emptyOption.value = ""; 973 emptyOption.textContent = placeholder; 974 select.appendChild(emptyOption); 975 976 choices.forEach(function(choice) { 977 const opt = document.createElement("option"); 978 opt.value = choice[valueKey] !== undefined ? String(choice[valueKey]) : (choice.value !== undefined ? String(choice.value) : ""); 979 opt.textContent = choice[textKey] !== undefined ? choice[textKey] : (choice.text !== undefined ? choice.text : opt.value); 980 if (String(question.value) === opt.value) opt.selected = true; 981 select.appendChild(opt); 982 }); 983 984 select.addEventListener("change", function() { 985 question.value = this.value === "" ? undefined : this.value; 986 }); 987 988 const wrap = document.createElement("div"); 989 wrap.className = "sd-dropdown-native-wrapper"; 990 wrap.appendChild(select); 991 992 const wrapper = root.querySelector(".sv-dropdown_select-wrapper") || root.querySelector(".sd-dropdown"); 993 if (wrapper) { 994 wrapper.replaceWith(wrap); 995 } else { 996 const content = root.querySelector(".sd-question__content") || root.querySelector(".sd-input"); 997 if (content) { 998 content.replaceWith(wrap); 999 } else { 1000 root.appendChild(wrap); 1001 } 1002 } 1003 } 1004 }); 1005 1006 1007 survey17.applyTheme({ 1008 "themeName": "defaultV2", 1009 "isPanelless": true 1010 }); 1011 survey17.questionErrorLocation = "bottom"; 1012 1013 (function scrollSurveyToTopOnStepChange() { 1014 var surveyModel = survey17; 1015 var formEl = document.getElementById('form-17'); 1016 1017 var scrollAboveFormPx = 100; 1018 1019 function scrollToFormTop() { 1020 if (formEl) { 1021 var rect = formEl.getBoundingClientRect(); 1022 var docY = window.pageYOffset || document.documentElement.scrollTop || 0; 1023 var y = rect.top + docY - scrollAboveFormPx; 1024 window.scrollTo({ top: Math.max(0, y), left: 0, behavior: 'auto' }); 1025 } else { 1026 window.scrollTo({ top: 0, left: 0, behavior: 'auto' }); 1027 } 1028 } 1029 1030 function scrollAfterLayout() { 1031 window.requestAnimationFrame(function () { 1032 window.requestAnimationFrame(scrollToFormTop); 1033 }); 1034 } 1035 1036 surveyModel.onCurrentPageChanged.add(function () { 1037 scrollAfterLayout(); 1038 SJT.syncCompleteButton(surveyModel, turnstileFormId); 1039 if (surveyModel.isLastPage && SJT.isContainerVisible(turnstileFormId)) { 1040 SJT.refreshVisibleWidgets(document.getElementById('form-' + turnstileFormId)); 1041 } 1042 }); 1043 1044 if (surveyModel.onShowingPreview && typeof surveyModel.onShowingPreview.add === 'function') { 1045 surveyModel.onShowingPreview.add(function () { 1046 scrollAfterLayout(); 1047 }); 1048 } 1049 })(); 1050 1051 1052 1053 1054 1055 1056// // Render the Survey 1057// document.addEventListener("DOMContentLoaded", function () { 1058// $("#surveyContainer").Survey({ model: survey9 }); 1059// }); 1060 1061 1062 1063 1064 1065/** 1066 * IMPORTANT: SurveyJS stores sender.data as a plain JS object. 1067 * Object keys are inserted in the order the user answers questions. 1068 * This function rebuilds a new object in the SURVEY DEFINITION ORDER. 1069 */ 1070function reorderObjectByKeys(obj, orderedKeys) { 1071 if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj; 1072 1073 const out = {}; 1074 // first: known keys in desired order 1075 orderedKeys.forEach(k => { 1076 if (Object.prototype.hasOwnProperty.call(obj, k)) out[k] = obj[k]; 1077 }); 1078 // then: any remaining keys (don't lose anything)
1079 Object.keys(obj).forEach(k => { 1080 if (!Object.prototype.hasOwnProperty.call(out, k)) out[k] = obj[k]; 1081 }); 1082 return out; 1083} 1084 1085function reorderDynamicPanelRows(question, rows) { 1086 if (!Array.isArray(rows)) return rows; 1087 1088 // templateElements defines the "design order" for fields inside each repeated panel 1089 const template = question && Array.isArray(question.templateElements) ? question.templateElements : []; 1090 const templateNames = template 1091 .map(el => el && el.name ? el.name : null) 1092 .filter(Boolean); 1093 1094 if (!templateNames.length) return rows; 1095 1096 return rows.map(row => reorderObjectByKeys(row, templateNames)); 1097} 1098 1099function reorderDynamicMatrixRows(question, rows) { 1100 if (!Array.isArray(rows)) return rows; 1101 1102 const cols = question && Array.isArray(question.columns) ? question.columns : []; 1103 const colNames = cols 1104 .map(c => (c && (c.name || c.value)) ? (c.name || c.value) : null) 1105 .filter(Boolean); 1106 1107 if (!colNames.length) return rows; 1108 1109 return rows.map(row => reorderObjectByKeys(row, colNames)); 1110} 1111 1112function reorderMultipleText(question, valueObj) { 1113 if (!valueObj || typeof valueObj !== "object" || Array.isArray(valueObj)) return valueObj; 1114 1115 const items = question && Array.isArray(question.items) ? question.items : []; 1116 const itemNames = items 1117 .map(i => i && i.name ? i.name : null) 1118 .filter(Boolean); 1119 1120 if (!itemNames.length) return valueObj; 1121 1122 return reorderObjectByKeys(valueObj, itemNames); 1123} 1124 1125/** 1126 * Builds submission data in SURVEY ORDER, and also fixes nested ordering 1127 * (Dynamic Panel / Dynamic Matrix / Multiple Text). 1128 */ 1129function getOrderedData(survey) { 1130 const data = survey.data || {}; 1131 const ordered = {}; 1132 1133 // Survey definition order for top-level keys 1134 const questions = survey.getAllQuestions(); 1135 1136 questions.forEach(q => { 1137 if (!q || !q.name) return; 1138 if (!Object.prototype.hasOwnProperty.call(data, q.name)) return; 1139 1140 const type = (typeof q.getType === "function" ? q.getType() : (q.getType || "")).toLowerCase(); 1141 let val = data[q.name]; 1142 1143 if (type === "paneldynamic") { 1144 val = reorderDynamicPanelRows(q, val); 1145 } else if (type === "matrixdynamic") { 1146 val = reorderDynamicMatrixRows(q, val); 1147 } else if (type === "multipletext") { 1148 val = reorderMultipleText(q, val); 1149 } else if (Array.isArray(val)) { 1150 // If it's an array of objects for some other reason, lightly normalize inner object key order 1151 // (keeps existing insertion order, but ensures deterministic output by reordering keys alphabetically is NOT desired here, 1152 // so we leave it as-is.) 1153 } else if (val && typeof val === "object") { 1154 // Nested plain objects (non-special types) - leave as-is 1155 } 1156 1157 ordered[q.name] = val; 1158 }); 1159 1160 // Include any extra keys that aren't actual questions (just in case) 1161 Object.keys(data).forEach(k => { 1162 if (!Object.prototype.hasOwnProperty.call(ordered, k)) { 1163 ordered[k] = data[k]; 1164 } 1165 }); 1166 1167 return ordered; 1168} 1169 1170// Function to make the form read-only and semi-transparent 1171function makeFormReadOnly(sender) { 1172 // Don't prevent completion - let SurveyJS show its completion page first 1173 // Make all questions read-only 1174 sender.getAllQuestions().forEach(question => { 1175 question.readOnly = true; 1176 }); 1177 1178 // Hide the navigation buttons 1179 const navButtons = document.querySelectorAll('.sd-navigation__btn'); 1180 navButtons.forEach(btn => { 1181 btn.style.display = 'none'; 1182 }); 1183 1184 // Add semi-transparent overlay to the form container 1185 const formContainer = document.getElementById('surveyContainer-17'); 1186 if (formContainer) { 1187 formContainer.style.opacity = '0.9'; 1188 formContainer.style.pointerEvents = 'none'; 1189 1190 // Check if overlay already exists, if so remove it first 1191 const existingOverlay = document.getElementById('success-overlay-17'); 1192 if (existingOverlay) { 1193 existingOverlay.remove(); 1194 } 1195 1196 // Add a success message overlay 1197 const successOverlay = document.createElement('div'); 1198 successOverlay.id = 'success-overlay-17'; 1199 successOverlay.style.cssText = `
1200 position: absolute; 1201 top: 0; 1202 left: 0; 1203 right: 0; 1204 bottom: 0; 1205 background: rgba(255, 255, 255, 0.5); 1206 display: flex !important; 1207 align-items: center; 1208 justify-content: center; 1209 z-index: 1000; 1210 pointer-events: none; 1211 `; 1212 1213 const successMessage = document.createElement('div'); 1214 successMessage.style.cssText = ` 1215 background: rgba(76, 175, 80, 0.9); 1216 color: white; 1217 padding: 20px; 1218 border-radius: 8px; 1219 text-align: center; 1220 font-weight: bold; 1221 box-shadow: 0 4px 8px rgba(0,0,0,0.2); 1222 `; 1223 1224 successMessage.innerHTML = "Thanks for reaching out to us, we\u0027ll be in touch soon."; 1225 1226 1227 successOverlay.appendChild(successMessage); 1228 1229 // Make the form container relative positioned to contain the overlay 1230 formContainer.style.position = 'relative'; 1231 formContainer.appendChild(successOverlay); 1232 } 1233} 1234 1235document.addEventListener("DOMContentLoaded", function() { 1236 survey17.render(document.getElementById("surveyContainer-17")); 1237 1238}); 1239 1240 1241 1242 1243function getLeadSource() { 1244 const p = new URLSearchParams(location.search); 1245 1246 // Google click identifiers (common) 1247 const hasGclid = p.has('gclid') || p.has('gbraid') || p.has('wbraid'); 1248 1249 // Fallback to UTMs if you use them 1250 const utmSource = (p.get('utm_source') || '').toLowerCase(); 1251 const utmMedium = (p.get('utm_medium') || '').toLowerCase(); 1252 1253 // "Google ads lead link" usually means a paid click, so treat any click id as Paid. 1254 if (hasGclid) return 'google_ads'; 1255 1256 // If you tag with UTMs, this catches paid traffic too 1257 if (utmSource === 'google' && (utmMedium === 'cpc' || utmMedium === 'ppc' || utmMedium === 'paid')) return 'google_ads'; 1258 1259 return 'organic_or_other'; 1260} 1261 1262function getAttributionParams() { 1263 const STORAGE_KEY = 'xrx_attribution_v1'; 1264 const p = new URLSearchParams(window.location.search); 1265 1266 // Pull only known keys (keeps storage tidy) 1267 const fromUrl = { 1268 // Standard UTMs 1269 utm_source: p.get('utm_source'), 1270 utm_medium: p.get('utm_medium'), 1271 utm_campaign: p.get('utm_campaign'), 1272 utm_term: p.get('utm_term'), 1273 utm_content: p.get('utm_content'), 1274 1275 // Common click IDs 1276 gclid: p.get('gclid'), 1277 gbraid: p.get('gbraid'), 1278 wbraid: p.get('wbraid'), 1279 fbclid: p.get('fbclid'), 1280 msclkid: p.get('msclkid') 1281 }; 1282 1283 // Read anything already stored 1284 let stored = {}; 1285 try { 1286 stored = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}') || {}; 1287 } catch (e) { 1288 stored = {}; 1289 } 1290 1291 // Merge: URL values win, but only if they are present (non-empty) 1292 const merged = { ...stored }; 1293 Object.keys(fromUrl).forEach((k) => { 1294 const v = fromUrl[k]; 1295 if (v !== null && v !== undefined && String(v).trim() !== '') { 1296 merged[k] = v; 1297 } 1298 }); 1299 1300 // If we captured anything new, write back to sessionStorage 1301 // (Also store first_seen timestamp for troubleshooting) 1302 const hasAny = 1303 Object.values(merged).some(v => v !== null && v !== undefined && String(v).trim() !== ''); 1304 1305 if (hasAny) { 1306 if (!merged.first_seen) merged.first_seen = new Date().toISOString(); 1307 try { 1308 sessionStorage.setItem(STORAGE_KEY, JSON.stringify(merged)); 1309 } catch (e) { 1310 // If storage fails (rare), just continue without breaking submit flow 1311 } 1312 } 1313 1314 // Return a clean object with nulls for missing keys (matches your existing shape) 1315 return { 1316 utm_source: merged.utm_source || null, 1317 utm_medium: merged.utm_medium || null, 1318 utm_campaign: merged.utm_campaign || null, 1319 utm_term: merged.utm_term || null, 1320 utm_content: merged.utm_content || null, 1321 gclid: merged.gclid || null, 1322 gbraid: merged.gbraid || null, 1323 wbraid: merged.wbraid || null, 1324 fbclid: merged.fbclid || null, 1325 msclkid: merged.msclkid || null 1326 }; 1327} 1328 1329function classifyLeadSource(attrs) { 1330 // Paid Google 1331 if (attrs.gclid || attrs.gbraid || attrs.wbraid) return 'google_ads'; 1332 1333 // Paid social (your convention) 1334 if ((attrs.utm_medium || '').toLowerCase() === 'paid_social') return 'paid_social'; 1335 1336 // Catch-all social if you ever use utm_medium=social 1337 if ((attrs.utm_medium || '').toLowerCase() === 'social') return 'organic_social'; 1338 1339 return 'organic_or_other'; 1340} 1341 1342 1343function getGTMData() { 1344 1345 const attrs = getAttributionParams(); 1346 const lead_source = classifyLeadSource(attrs); 1347 const page_location = window.location.href; 1348 const page_path = window.location.pathname; 1349 1350 window.dataLayer = window.dataLayer || []; 1351 window.dataLayer.push({ 1352 event: 'formCompleted', 1353 form_name: "Get In Touch", 1354 page_path: page_path, 1355 page_location: page_location, 1356 submission_time: new Date().toISOString(), 1357 1358 // Attribution bundle 1359 lead_source: lead_source, 1360 utm_source: attrs.utm_source, 1361 utm_medium: attrs.utm_medium, 1362 utm_campaign: attrs.utm_campaign, 1363 utm_term: attrs.utm_term,
1364 utm_content: attrs.utm_content, 1365 gclid: attrs.gclid, 1366 gbraid: attrs.gbraid, 1367 wbraid: attrs.wbraid, 1368 fbclid: attrs.fbclid, 1369 msclkid: attrs.msclkid 1370 }); 1371 1372} 1373 1374 1375 1376function alertResultsPayment (sender) { 1377 1378 // loop through all fields and if none of the fields have the class is-payment-dropdown, then run the non-payment alertResults 1379 const fields = sender.getAllQuestions(); 1380 let hasPaymentDropdown = false; 1381 fields.forEach(field => { 1382 if (typeof field.jsonObj.class !== "undefined" && field.jsonObj.class === "is-payment-dropdown") { 1383 if (field.isVisible) { 1384 hasPaymentDropdown = true; 1385 } 1386 } 1387 }); 1388 if ( !hasPaymentDropdown ) { 1389 survey17.completedHtml = `<div class="surveyjs-thankyou"><h2 class="surveyjs-thankyou__title">Get In Touch</h2><p class="surveyjs-thankyou__message">Thank you. Your form has been submitted successfully.</p></div>`; 1390 survey17.showCompletedPage = true; 1391 return alertResults(sender); 1392 } 1393 1394 // Build ordered results (definition order, not "filled" order) 1395 const orderedData = getOrderedData(sender); 1396 const results = JSON.stringify(orderedData); 1397 1398 var turnstileToken = SJT.getTokenForSubmit(turnstileFormId); 1399 1400 // Get the values from hidden input fields 1401 const formid = document.getElementById('formid-17').value; 1402 const pageurl = document.getElementById('pageurl').value; 1403 const paymentElements = document.getElementById('paymentElements-17').value; 1404 1405 // Create a new form element dynamically 1406 const form = document.createElement("form"); 1407 form.method = "POST"; 1408 form.action = "/service/index/proxysjs/"; 1409 1410 // Function to add hidden input fields to the form 1411 function addHiddenField(name, value) { 1412 if (value !== undefined && value !== null) { 1413 let input = document.createElement("input"); 1414 input.type = "hidden"; 1415 input.name = name; 1416 input.value = value; 1417 form.appendChild(input); 1418 } 1419 } 1420 1421 // Append fields to the form 1422 addHiddenField("formid", formid); 1423 addHiddenField("pageurl", pageurl); 1424 addHiddenField("cf-turnstile-response", turnstileToken); 1425 addHiddenField("ajax", "1"); 1426 addHiddenField("data", results); 1427 addHiddenField("paymentElements", paymentElements); 1428 1429 // If stripeToken exists, append it 1430 const stripeTokenElement = document.getElementById("stripeToken"); 1431 if (stripeTokenElement) { 1432 addHiddenField("stripeToken", stripeTokenElement.value); 1433 } 1434 1435 getGTMData(); 1436 1437 // Show thank you message before submitting (since form.submit() navigates away) 1438 makeFormReadOnly(sender); 1439 1440 const surveyHolder = document.querySelector('#form-17').closest('.surveyjs-holder'); 1441 if (surveyHolder ) { 1442 surveyHolder.classList.add('surveyjs-submitted'); 1443 surveyHolder.innerHTML = '<h2 class="form-title">Get In Touch</h2><p class="extracontent1">Redirecting you to a secure payment page ...</p>'; 1444 } 1445 1446 // Append the form to the body and submit it (after showing message) 1447 document.body.appendChild(form); 1448 setTimeout(() => { 1449 form.submit(); 1450 }, 500); // Small delay to let user see the thank you message 1451 1452} 1453 1454function handleFormSubmissionResult(sender, surveyHolder, status, data, isNetworkError) { 1455 const container = document.getElementById('surveyContainer-17'); 1456 const completedPage = container && container.querySelector('.sd-completedpage'); 1457 1458 // Clear any previous error 1459 if (container) { 1460 const existingError = container.querySelector('.surveyjs-submit-error'); 1461 if (existingError) existingError.remove(); 1462 } 1463 1464 // Network-level failure 1465 if (isNetworkError) { 1466 if (surveyHolder) { 1467 surveyHolder.classList.remove('surveyjs-submitted'); 1468 } 1469 if (completedPage) { 1470 completedPage.style.display = 'none'; 1471 } 1472 const errEl = document.createElement('p'); 1473 errEl.className = 'surveyjs-submit-error'; 1474 errEl.setAttribute('role', 'alert'); 1475 errEl.style.color = '#b21f03'; 1476 errEl.style.marginTop = '1em'; 1477 errEl.textContent = 'Form error. Please check your connection and try again.'; 1478 if (container) { 1479 container.appendChild(errEl); 1480 } 1481 return; 1482 } 1483 1484 // Success from backend 1485 if (status === 200 && data === 'success') { 1486 // console.log('Success: ' + data); 1487 getGTMData(); 1488 setTimeout(() => { 1489 makeFormReadOnly(sender); 1490 }, 300); 1491 if (completedPage) { 1492 completedPage.style.display = ''; 1493 } 1494 return; 1495 } 1496 1497 // Turnstile / robot validation failure: 403 or Cloudflare challenge body 1498 const looksLikeTurnstileFailure = 1499 status === 403 || 1500 (data && (data.indexOf('Just a moment') !== -1 || data.indexOf('challenges.cloudflare.com') !== -1)); 1501 1502 if (surveyHolder) { 1503 surveyHolder.classList.remove('surveyjs-submitted'); 1504 } 1505 if (completedPage) { 1506 completedPage.style.display = 'none'; 1507 } 1508 1509 const errEl = document.createElement('p'); 1510 errEl.className = 'surveyjs-submit-error'; 1511 errEl.setAttribute('role', 'alert'); 1512 errEl.style.color = '#b21f03'; 1513 errEl.style.marginTop = '1em'; 1514 errEl.textContent = looksLikeTurnstileFailure 1515 ? 'Security check failed or expired. Please complete it again and resubmit.' 1516 : 'Form error. Please try again.'; 1517 1518 if (container) { 1519 container.appendChild(errEl); 1520 } 1521 1522 if (looksLikeTurnstileFailure) { 1523 SJT.resetWidget(turnstileFormId); 1524 SJT.syncCompleteButton(sender, turnstileFormId); 1525 } 1526} 1527 1528function alertResults (sender) { 1529 // Build ordered results (definition order, not "filled" order) 1530 const orderedData = getOrderedData(sender); 1531 const results = JSON.stringify(orderedData); 1532 1533 // Post these results to a url using javascript fetch or any other library 1534 // Create a new FormData object 1535 const formData = new FormData(); 1536 var turnstileToken = SJT.getTokenForSubmit(turnstileFormId); 1537 1538 // Get the values from the hidden input fields 1539 const formid = document.getElementById('formid-17').value; 1540 const pageurl = document.getElementById('pageurl').value; 1541 1542 // Get the paymentElements from the hidden input field 1543 const paymentElements = document.getElementById('paymentElements-17').value; 1544 1545 // If the form id stripeToken exists then add it to the form data 1546 if (document.getElementById('stripeToken')) { 1547 formData.append('stripeToken', document.getElementById('stripeToken').value); 1548 } 1549 1550 // Add your data as individual key-value pairs 1551 formData.append('formid', formid); 1552 formData.append('pageurl', pageurl); 1553 formData.append('cf-turnstile-response', turnstileToken); 1554 formData.append('ajax', 1); 1555 // IMPORTANT: results is already a JSON string; DO NOT JSON.stringify it again 1556 formData.append('data', results); 1557 formData.append('paymentElements', paymentElements); 1558 1559 // Add class to surveyjs-holder on successful submission 1560 const surveyHolder = document.querySelector('#form-17').closest('.surveyjs-holder'); 1561 if (surveyHolder) { 1562 surveyHolder.classList.add('surveyjs-submitted'); 1563 } 1564 1565 const yOffset = -280; 1566 const y = document.querySelector('#form-17').getBoundingClientRect().top + window.pageYOffset + yOffset; 1567 window.scrollTo({ top: y, behavior: 'smooth' }); 1568 1569 // Send the FormData object using fetch 1570 // Note: 403 here is often Cloudflare blocking the POST (e.g. when payload includes file upload data). 1571 // Add a WAF/Page Rule exception for /service/index/proxysjs/ in Cloudflare if submissions with files fail. 1572 fetch('/service/index/proxysjs/', { 1573 method: 'POST', 1574 body: formData, 1575 }) 1576 .then(response => { 1577 const status = response.status; 1578 return response.text().then(text => ({ status, text })); 1579 }) 1580 .then(({ status, text }) => { 1581 handleFormSubmissionResult(sender, surveyHolder, status, text, false); 1582 }) 1583 .catch(() => {
1584 handleFormSubmissionResult(sender, surveyHolder, 0, '', true); 1585 }); 1586} 1587 1588// Validate Turnstile before allowing survey completion 1589survey17.onCompleting.add((sender, options) => { 1590 var token = SJT.getTokenForSubmit(turnstileFormId); 1591 1592 if (!token) { 1593 options.allowComplete = false; 1594 SJT.showError(turnstileFormId, 'Please complete the security check below before submitting.'); 1595 SJT.syncCompleteButton(sender, turnstileFormId); 1596 return; 1597 } 1598 1599 SJT.clearError(turnstileFormId); 1600 1601 survey17.completedHtml = "\u003Cdiv class=\u0022surveyjs-thankyou\u0022\u003E\u003Ch2 class=\u0022surveyjs-thankyou__title\u0022\u003EGet In Touch\u003C\/h2\u003E\u003Cp class=\u0022surveyjs-thankyou__message\u0022\u003EThanks for reaching out to us, we\u0027ll be in touch soon.\u003C\/p\u003E\u003C\/div\u003E"; 1602 }); 1603survey17.onAfterRenderSurvey.add(() => { 1604 SJT.syncCompleteButton(survey17, turnstileFormId); 1605}); 1606 survey17.onComplete.add(alertResults); 1607 1608 })(); 1609 1610 </script>
1610 1611</div> </div> 1612 <div class="footer-copyright footer-copyright--sm"> 1613 <p> 1614 © 2026 POA 1615 <span>|</span> <a href="/sitemap/">Sitemap</a> 1616 <span>|</span> <a href="/privacy-policy/">Privacy Policy</a> 1617 </p> 1618 <p>Site by <a aria-label="OracleStudio" target="_blank" rel="noopener noreferrer" href="https://www.oraclestudio.com.au">OracleStudio</a> <span>|</span> 1619 Design by <a aria-label="Novellus" target="_blank" rel="noopener noreferrer" href="javascript:;">Novellus</a></p> 1620 </div> 1621 </div> 1622 <a href="javascript:;" data-href="body" class="back-to-top scrollto"> 1623 <span class="back-to-top-icon"> 1624 <svg height="15.5" viewBox="0 0 15.5 15.5" width="15.5" xmlns="http://www.w3.org/2000/svg"><path d="m12 4.25.27.054.012.001.005.003c.008.002.004 0 .012.008l.231.154 7 7c.293.293.293.767 0 1.06s-.767.293-1.06 0l-5.72-5.719v12.189c0 .414-.336.75-.75.75s-.75-.336-.75-.75v-12.189l-5.72 5.719c-.293.293-.767.293-1.06 0s-.293-.767 0-1.06l7-7c.158-.113.087-.08.2-.123.108-.108.02-.035.33-.097z" fill="#001d3c" transform="translate(-4.25 -4.25)"/></svg> </span> 1625 <span class="back-to-top-title">Top</span> 1626 </a> 1627 </footer> 1628 </div> 1629 <div class="mm-menu-bg"></div> 1630 <div class="mm-menu"> 1631 <div class="mm-menu-content"> 1632 <div class="mm-menu-nav"></div> 1633 <div class="mm-menu-social"> 1634 <span class="h6">Let's Get <span>Social</span></span> 1635 <ul class="reset"> 1636 <li> 1637 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.facebook.com/POABillboards/" aria-label="Facebook"> 1638 <svg fill="none" height="19" viewBox="0 0 10 19" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m9.18359 10.375h-2.63671v7.875h-3.51563v-7.875h-2.882812v-3.23438h2.882812v-2.49609c0-2.8125 1.6875-4.39453 4.25391-4.39453 1.23046 0 2.53125.246094 2.53125.246094v2.777346h-1.44141c-1.40625 0-1.82812.84375-1.82812 1.75781v2.10937h3.1289z" fill="#001d3c"/></svg> <span>Facebook</span> 1639 </a> 1640 </li> 1641 <li> 1642 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.instagram.com/poa_billboards/" aria-label="Instagram"> 1643 <svg fill="none" height="17" viewBox="0 0 16 17" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 4.20703c2.2148 0 4.043 1.82813 4.043 4.04297 0 2.25-1.8282 4.043-4.043 4.043-2.25 0-4.04297-1.793-4.04297-4.043 0-2.21484 1.79297-4.04297 4.04297-4.04297zm0 6.67967c1.44141 0 2.6016-1.16014 2.6016-2.6367 0-1.44141-1.16019-2.60156-2.6016-2.60156-1.47656 0-2.63672 1.16015-2.63672 2.60156 0 1.47656 1.19531 2.6367 2.63672 2.6367zm5.1328-6.82029c0-.52735-.4219-.94922-.9492-.94922-.5274 0-.9492.42187-.9492.94922 0 .52734.4218.94921.9492.94921.5273 0 .9492-.42187.9492-.94921zm2.6719.94921c.0703 1.30079.0703 5.20318 0 6.50388-.0703 1.2657-.3516 2.3555-1.2656 3.3047-.9141.9141-2.0391 1.1953-3.3047 1.2656-1.30081.0704-5.20315.0704-6.50393 0-1.26563-.0703-2.35547-.3515-3.30469-1.2656-.914061-.9492-1.195311-2.039-1.265624-3.3047-.0703122-1.3007-.0703122-5.20309 0-6.50388.070313-1.26562.351563-2.39062 1.265624-3.30468.94922-.914065 2.03906-1.195315 3.30469-1.265628 1.30078-.070312 5.20312-.070312 6.50393 0 1.2656.070313 2.3906.351563 3.3047 1.265628.914.91406 1.1953 2.03906 1.2656 3.30468zm-1.6875 7.87498c.4219-1.0195.3164-3.48044.3164-4.6406 0-1.125.1055-3.58594-.3164-4.64062-.2813-.66797-.8086-1.23047-1.4766-1.47657-1.0547-.42187-3.5156-.3164-4.6406-.3164-1.16016 0-3.62109-.10547-4.64062.3164-.70313.28125-1.23047.8086-1.51172 1.47657-.42188 1.05468-.31641 3.51562-.31641 4.64062 0 1.16016-.10547 3.6211.31641 4.6406.28125.7032.80859 1.2305 1.51172 1.5117 1.01953.4219 3.48046.3165 4.64062.3165 1.125 0 3.5859.1054 4.6406-.3165.668-.2812 1.2305-.8085 1.4766-1.5117z" fill="#001d3c"/></svg> <span>Instagram</span> 1644 </a> 1645 </li> 1646 <li> 1647 <a rel="nofollow noopener noreferrer" target="_blank" href="https://www.linkedin.com/company/poabillboards" aria-label="LinkedIn"> 1648 <svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg"> 1649<path fill-rule="evenodd" clip-rule="evenodd" d="M0.182196 13.655H3.25363V4.4415H0.182196V13.655ZM1.71748 3.18394C2.78821 3.18394 3.45568 2.47554 3.45568 1.59154C3.43582 0.687744 2.78821 0 1.73734 0C0.686474 0 0 0.686884 0 1.59068C0 2.47554 0.666614 3.18308 1.69848 3.18308H1.71748V3.18394ZM14.3322 13.655V8.37258C14.3322 5.54241 12.8168 4.22545 10.7953 4.22545C9.16421 4.22545 8.4337 5.11978 8.02699 5.74727V4.4415H4.9547C4.99528 5.30656 4.9547 13.655 4.9547 13.655H8.02699V8.50944C8.02699 8.23486 8.04685 7.95942 8.12802 7.76316C8.34994 7.21314 8.85508 6.64332 9.70389 6.64332C10.8161 6.64332 11.2608 7.48772 11.2608 8.72635V13.6559L14.3322 13.655Z" fill="#003B4A"/> 1650</svg> 1651 <span>LinkedIn</span> 1652 </a> 1653 </li> 1654 </ul> 1655 </div> 1656 </div> 1657 </div> 1658 <div class="sticky-tab"> 1659 <button data-fancybox data-src="#modal-enquire">Enquire Now</button> 1660 </div> 1661 <div id="modal-enquire" class="modal modal-enquire"> 1662 <style> 1663 1664.success-overlay-21, #success-overlay-21 { 1665 display: none !important; 1666 opacity: 0 !important; 1667 visibility: hidden !important; 1668 pointer-events: none !important; 1669} 1670 1671</style> 1672<div id="form-21" class="surveyjs-holder" data-load="surveyjs" data-load-css data-load-js data-load-type="force"> 1673 <input id="formid-21" type="hidden" value="21" name="formid" /> 1674 <input id="pageurl" class="form-page-url" type="hidden" value="/" name="pageurl" /> 1675 <input id="paymentElements-21" type="hidden" value="" name="paymentElements" /> 1676 <div class="surveyjs-form-shell"> 1677 <h3 class="form-title">Enquire Now</h3> 1678 <div id="surveyContainer-21"></div> 1679 </div>
1680<script> 1681 1682Survey.surveyLocalization.getLocaleStrings("en").filePlaceholder = 1683 "Drag and drop a file here or click the button below to select a file to upload."; 1684 1685 1686 1687 1688 var surveyJSON21 = {"pages":[{"name":"page1","elements":[{"type":"text","name":"question1","title":"First Name","isRequired":true},{"type":"text","name":"question2","startWithNewLine":false,"title":"Surname","isRequired":true},{"type":"text","name":"question3","title":"Company"},{"type":"text","name":"question4","startWithNewLine":false,"title":"Position"},{"type":"dropdown","name":"question5","title":"What region are you interested in?","choices":[{"value":"item1","text":"Airlie Beach"},{"value":"item2","text":"Augathella"},{"value":"item3","text":"Biloela"},{"value":"item4","text":"Brisbane"},{"value":"item5","text":"Bowen"},{"value":"item6","text":"Cairns"},{"value":"item7","text":"Charters Towers"},{"value":"item8","text":"Chinchilla"},{"value":"item9","text":"Clermont"},{"value":"item10","text":"Dalby"},{"value":"item11","text":"Emerald"},{"value":"item12","text":"Giru"},{"value":"item13","text":"Gladstone"},{"value":"item14","text":"Goondiwindi"},{"value":"item15","text":"Hervey Bay"},{"value":"item16","text":"Hughenden"},{"value":"item17","text":"Hinchinbrook"},{"value":"item18","text":"Innisfail"},{"value":"item19","text":"Julia Creek"},{"value":"item20","text":"Mackay"},{"value":"item21","text":"Maryborough"},{"value":"item22","text":"Miles"},{"value":"item23","text":"Milaa Milaa"},{"value":"item24","text":"Mount Isa"},{"value":"item25","text":"Port Douglas"},{"value":"item26","text":"Richmond"},{"value":"item27","text":"St George"},{"value":"item28","text":"Tablelands"},{"value":"item29","text":"Toowoomba"},{"value":"item30","text":"Townsville"},{"value":"item31","text":"Tully"},{"value":"item32","text":"Winton"}]},{"type":"text","name":"question6","title":"Phone Number","isRequired":true},{"type":"text","name":"question7","startWithNewLine":false,"title":"Email Address","isRequired":true,"inputType":"email"},{"type":"text","name":"question8","title":"Address","isRequired":true},{"type":"text","name":"question9","startWithNewLine":false,"title":"Suburb \/ City","isRequired":true},{"type":"text","name":"question10","title":"State","isRequired":true},{"type":"text","name":"question11","startWithNewLine":false,"title":"Postcode","isRequired":true},{"type":"comment","name":"question12","title":"Your Message"},{"type":"html","name":"turnstile-widget","title":"Security check","html":"<div id='turnstile-container-21' data-form-id='21'><div class='cf-turnstile-surveyjs' data-appearance='interaction-only' data-sitekey='0x4AAAAAAAfn5Ry99YNSWl_B' data-theme='light'><\/div><\/div>"}]}]}; 1689 var survey21 = new Survey.Model(surveyJSON21); 1690 1691 // Signature pad: pen color (canvas API does not support CSS variables) and optional dimensions 1692 (function() { 1693 var survey = survey21; 1694 var root = document.documentElement; 1695 var resolved = getComputedStyle(root).getPropertyValue('--colorSecondary').trim(); 1696 var sigWidth = 1400; 1697 var sigHeight = 300; 1698 survey.getAllQuestions().forEach(function(q) { 1699 if (q.getType() === 'signaturepad') { 1700 if (resolved) q.penColor = resolved; 1701 if (sigWidth != null && sigWidth > 0) q.signatureWidth = sigWidth; 1702 if (sigHeight != null && sigHeight > 0) q.signatureHeight = sigHeight; 1703 } 1704 }); 1705 })(); 1706 1707 (function() { 1708 var turnstileFormId = '21'; 1709 var surveyTurnstile = survey21; 1710 var SJT = window.SurveyJsTurnstile; 1711 1712 survey21.onAfterRenderQuestion.add(function (survey, options) { 1713 if (options.question.name === "turnstile-widget") { 1714 const formId = turnstileFormId; 1715 const hasWidget = SJT.hasLiveWidget(formId); 1716 const hasToken = !!SJT.getTokenForSubmit(formId); 1717 1718 // Only render while visible; hidden modals refresh on Fancybox reveal. 1719 if (SJT.isContainerVisible(formId) && (!hasWidget || !hasToken)) { 1720 SJT.rerenderWidget(formId, surveyTurnstile); 1721 } else { 1722 SJT.syncCompleteButton(surveyTurnstile, formId); 1723 } 1724 } else if (options.question.getType() === "dropdown") {
1725 // Replace SurveyJS custom dropdown with native <select> (e.g. for Fancybox compatibility) 1726 const question = options.question; 1727 const root = options.htmlElement; 1728 if (root.querySelector("select.sd-dropdown-native")) return; 1729 1730 const choices = question.visibleChoices || question.choices || []; 1731 const valueKey = question.valuePropertyName || "value"; 1732 const textKey = question.textPropertyName || "text"; 1733 1734 const select = document.createElement("select"); 1735 select.setAttribute("aria-label", question.title); 1736 select.className = "sd-input sd-dropdown sd-dropdown-native"; 1737 1738 if ( question.jsonObj.class && question.jsonObj.class === "is-payment-dropdown") { 1739 select.classList.add("is-payment-dropdown"); 1740 } 1741 1742 select.id = question.inputId; 1743 if (question.isRequired) select.required = true; 1744 if (question.readOnly) select.disabled = true; 1745 1746 const placeholder = question.placeholder || question.optionsCaption || "Select..."; 1747 const emptyOption = document.createElement("option"); 1748 emptyOption.value = ""; 1749 emptyOption.textContent = placeholder; 1750 select.appendChild(emptyOption); 1751 1752 choices.forEach(function(choice) { 1753 const opt = document.createElement("option"); 1754 opt.value = choice[valueKey] !== undefined ? String(choice[valueKey]) : (choice.value !== undefined ? String(choice.value) : ""); 1755 opt.textContent = choice[textKey] !== undefined ? choice[textKey] : (choice.text !== undefined ? choice.text : opt.value); 1756 if (String(question.value) === opt.value) opt.selected = true; 1757 select.appendChild(opt); 1758 }); 1759 1760 select.addEventListener("change", function() { 1761 question.value = this.value === "" ? undefined : this.value; 1762 }); 1763 1764 const wrap = document.createElement("div"); 1765 wrap.className = "sd-dropdown-native-wrapper"; 1766 wrap.appendChild(select); 1767 1768 const wrapper = root.querySelector(".sv-dropdown_select-wrapper") || root.querySelector(".sd-dropdown"); 1769 if (wrapper) { 1770 wrapper.replaceWith(wrap); 1771 } else { 1772 const content = root.querySelector(".sd-question__content") || root.querySelector(".sd-input"); 1773 if (content) { 1774 content.replaceWith(wrap); 1775 } else { 1776 root.appendChild(wrap); 1777 } 1778 } 1779 } 1780 }); 1781 1782 1783 survey21.applyTheme({ 1784 "themeName": "defaultV2", 1785 "isPanelless": true 1786 }); 1787 survey21.questionErrorLocation = "bottom"; 1788 1789 (function scrollSurveyToTopOnStepChange() { 1790 var surveyModel = survey21; 1791 var formEl = document.getElementById('form-21'); 1792 1793 var scrollAboveFormPx = 100; 1794 1795 function scrollToFormTop() { 1796 if (formEl) { 1797 var rect = formEl.getBoundingClientRect(); 1798 var docY = window.pageYOffset || document.documentElement.scrollTop || 0; 1799 var y = rect.top + docY - scrollAboveFormPx; 1800 window.scrollTo({ top: Math.max(0, y), left: 0, behavior: 'auto' }); 1801 } else { 1802 window.scrollTo({ top: 0, left: 0, behavior: 'auto' }); 1803 } 1804 } 1805 1806 function scrollAfterLayout() { 1807 window.requestAnimationFrame(function () { 1808 window.requestAnimationFrame(scrollToFormTop); 1809 }); 1810 } 1811 1812 surveyModel.onCurrentPageChanged.add(function () { 1813 scrollAfterLayout(); 1814 SJT.syncCompleteButton(surveyModel, turnstileFormId); 1815 if (surveyModel.isLastPage && SJT.isContainerVisible(turnstileFormId)) { 1816 SJT.refreshVisibleWidgets(document.getElementById('form-' + turnstileFormId)); 1817 } 1818 }); 1819 1820 if (surveyModel.onShowingPreview && typeof surveyModel.onShowingPreview.add === 'function') { 1821 surveyModel.onShowingPreview.add(function () { 1822 scrollAfterLayout(); 1823 }); 1824 } 1825 })(); 1826 1827 1828 1829 1830 1831 1832// // Render the Survey 1833// document.addEventListener("DOMContentLoaded", function () { 1834// $("#surveyContainer").Survey({ model: survey9 }); 1835// }); 1836 1837 1838 1839 1840 1841/** 1842 * IMPORTANT: SurveyJS stores sender.data as a plain JS object. 1843 * Object keys are inserted in the order the user answers questions. 1844 * This function rebuilds a new object in the SURVEY DEFINITION ORDER. 1845 */ 1846function reorderObjectByKeys(obj, orderedKeys) { 1847 if (!obj || typeof obj !== "object" || Array.isArray(obj)) return obj; 1848 1849 const out = {}; 1850 // first: known keys in desired order 1851 orderedKeys.forEach(k => { 1852 if (Object.prototype.hasOwnProperty.call(obj, k)) out[k] = obj[k]; 1853 }); 1854 // then: any remaining keys (don't lose anything)
1855 Object.keys(obj).forEach(k => { 1856 if (!Object.prototype.hasOwnProperty.call(out, k)) out[k] = obj[k]; 1857 }); 1858 return out; 1859} 1860 1861function reorderDynamicPanelRows(question, rows) { 1862 if (!Array.isArray(rows)) return rows; 1863 1864 // templateElements defines the "design order" for fields inside each repeated panel 1865 const template = question && Array.isArray(question.templateElements) ? question.templateElements : []; 1866 const templateNames = template 1867 .map(el => el && el.name ? el.name : null) 1868 .filter(Boolean); 1869 1870 if (!templateNames.length) return rows; 1871 1872 return rows.map(row => reorderObjectByKeys(row, templateNames)); 1873} 1874 1875function reorderDynamicMatrixRows(question, rows) { 1876 if (!Array.isArray(rows)) return rows; 1877 1878 const cols = question && Array.isArray(question.columns) ? question.columns : []; 1879 const colNames = cols 1880 .map(c => (c && (c.name || c.value)) ? (c.name || c.value) : null) 1881 .filter(Boolean); 1882 1883 if (!colNames.length) return rows; 1884 1885 return rows.map(row => reorderObjectByKeys(row, colNames)); 1886} 1887 1888function reorderMultipleText(question, valueObj) { 1889 if (!valueObj || typeof valueObj !== "object" || Array.isArray(valueObj)) return valueObj; 1890 1891 const items = question && Array.isArray(question.items) ? question.items : []; 1892 const itemNames = items 1893 .map(i => i && i.name ? i.name : null) 1894 .filter(Boolean); 1895 1896 if (!itemNames.length) return valueObj; 1897 1898 return reorderObjectByKeys(valueObj, itemNames); 1899} 1900 1901/** 1902 * Builds submission data in SURVEY ORDER, and also fixes nested ordering 1903 * (Dynamic Panel / Dynamic Matrix / Multiple Text). 1904 */ 1905function getOrderedData(survey) { 1906 const data = survey.data || {}; 1907 const ordered = {}; 1908 1909 // Survey definition order for top-level keys 1910 const questions = survey.getAllQuestions(); 1911 1912 questions.forEach(q => { 1913 if (!q || !q.name) return; 1914 if (!Object.prototype.hasOwnProperty.call(data, q.name)) return; 1915 1916 const type = (typeof q.getType === "function" ? q.getType() : (q.getType || "")).toLowerCase(); 1917 let val = data[q.name]; 1918 1919 if (type === "paneldynamic") { 1920 val = reorderDynamicPanelRows(q, val); 1921 } else if (type === "matrixdynamic") { 1922 val = reorderDynamicMatrixRows(q, val); 1923 } else if (type === "multipletext") { 1924 val = reorderMultipleText(q, val); 1925 } else if (Array.isArray(val)) { 1926 // If it's an array of objects for some other reason, lightly normalize inner object key order 1927 // (keeps existing insertion order, but ensures deterministic output by reordering keys alphabetically is NOT desired here, 1928 // so we leave it as-is.) 1929 } else if (val && typeof val === "object") { 1930 // Nested plain objects (non-special types) - leave as-is 1931 } 1932 1933 ordered[q.name] = val; 1934 }); 1935 1936 // Include any extra keys that aren't actual questions (just in case) 1937 Object.keys(data).forEach(k => { 1938 if (!Object.prototype.hasOwnProperty.call(ordered, k)) { 1939 ordered[k] = data[k]; 1940 } 1941 }); 1942 1943 return ordered; 1944} 1945 1946// Function to make the form read-only and semi-transparent 1947function makeFormReadOnly(sender) { 1948 // Don't prevent completion - let SurveyJS show its completion page first 1949 // Make all questions read-only 1950 sender.getAllQuestions().forEach(question => { 1951 question.readOnly = true; 1952 }); 1953 1954 // Hide the navigation buttons 1955 const navButtons = document.querySelectorAll('.sd-navigation__btn'); 1956 navButtons.forEach(btn => { 1957 btn.style.display = 'none'; 1958 }); 1959 1960 // Add semi-transparent overlay to the form container 1961 const formContainer = document.getElementById('surveyContainer-21'); 1962 if (formContainer) { 1963 formContainer.style.opacity = '0.9'; 1964 formContainer.style.pointerEvents = 'none'; 1965 1966 // Check if overlay already exists, if so remove it first 1967 const existingOverlay = document.getElementById('success-overlay-21'); 1968 if (existingOverlay) { 1969 existingOverlay.remove(); 1970 } 1971 1972 // Add a success message overlay 1973 const successOverlay = document.createElement('div'); 1974 successOverlay.id = 'success-overlay-21'; 1975 successOverlay.style.cssText = `
1976 position: absolute; 1977 top: 0; 1978 left: 0; 1979 right: 0; 1980 bottom: 0; 1981 background: rgba(255, 255, 255, 0.5); 1982 display: flex !important; 1983 align-items: center; 1984 justify-content: center; 1985 z-index: 1000; 1986 pointer-events: none; 1987 `; 1988 1989 const successMessage = document.createElement('div'); 1990 successMessage.style.cssText = ` 1991 background: rgba(76, 175, 80, 0.9); 1992 color: white; 1993 padding: 20px; 1994 border-radius: 8px; 1995 text-align: center; 1996 font-weight: bold; 1997 box-shadow: 0 4px 8px rgba(0,0,0,0.2); 1998 `; 1999 2000 successMessage.innerHTML = 'Form submitted successfully!'; 2001 2002 successOverlay.appendChild(successMessage); 2003 2004 // Make the form container relative positioned to contain the overlay 2005 formContainer.style.position = 'relative'; 2006 formContainer.appendChild(successOverlay); 2007 } 2008} 2009 2010document.addEventListener("DOMContentLoaded", function() { 2011 survey21.render(document.getElementById("surveyContainer-21")); 2012 2013}); 2014 2015 2016 2017 2018function getLeadSource() { 2019 const p = new URLSearchParams(location.search); 2020 2021 // Google click identifiers (common) 2022 const hasGclid = p.has('gclid') || p.has('gbraid') || p.has('wbraid'); 2023 2024 // Fallback to UTMs if you use them 2025 const utmSource = (p.get('utm_source') || '').toLowerCase(); 2026 const utmMedium = (p.get('utm_medium') || '').toLowerCase(); 2027 2028 // "Google ads lead link" usually means a paid click, so treat any click id as Paid. 2029 if (hasGclid) return 'google_ads'; 2030 2031 // If you tag with UTMs, this catches paid traffic too 2032 if (utmSource === 'google' && (utmMedium === 'cpc' || utmMedium === 'ppc' || utmMedium === 'paid')) return 'google_ads'; 2033 2034 return 'organic_or_other'; 2035} 2036 2037function getAttributionParams() { 2038 const STORAGE_KEY = 'xrx_attribution_v1'; 2039 const p = new URLSearchParams(window.location.search); 2040 2041 // Pull only known keys (keeps storage tidy) 2042 const fromUrl = { 2043 // Standard UTMs 2044 utm_source: p.get('utm_source'), 2045 utm_medium: p.get('utm_medium'), 2046 utm_campaign: p.get('utm_campaign'), 2047 utm_term: p.get('utm_term'), 2048 utm_content: p.get('utm_content'), 2049 2050 // Common click IDs 2051 gclid: p.get('gclid'), 2052 gbraid: p.get('gbraid'), 2053 wbraid: p.get('wbraid'), 2054 fbclid: p.get('fbclid'), 2055 msclkid: p.get('msclkid') 2056 }; 2057 2058 // Read anything already stored 2059 let stored = {}; 2060 try { 2061 stored = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}') || {}; 2062 } catch (e) { 2063 stored = {}; 2064 } 2065 2066 // Merge: URL values win, but only if they are present (non-empty) 2067 const merged = { ...stored }; 2068 Object.keys(fromUrl).forEach((k) => { 2069 const v = fromUrl[k]; 2070 if (v !== null && v !== undefined && String(v).trim() !== '') { 2071 merged[k] = v; 2072 } 2073 }); 2074 2075 // If we captured anything new, write back to sessionStorage 2076 // (Also store first_seen timestamp for troubleshooting) 2077 const hasAny = 2078 Object.values(merged).some(v => v !== null && v !== undefined && String(v).trim() !== ''); 2079 2080 if (hasAny) { 2081 if (!merged.first_seen) merged.first_seen = new Date().toISOString(); 2082 try { 2083 sessionStorage.setItem(STORAGE_KEY, JSON.stringify(merged)); 2084 } catch (e) { 2085 // If storage fails (rare), just continue without breaking submit flow 2086 } 2087 } 2088 2089 // Return a clean object with nulls for missing keys (matches your existing shape) 2090 return { 2091 utm_source: merged.utm_source || null, 2092 utm_medium: merged.utm_medium || null, 2093 utm_campaign: merged.utm_campaign || null, 2094 utm_term: merged.utm_term || null, 2095 utm_content: merged.utm_content || null, 2096 gclid: merged.gclid || null, 2097 gbraid: merged.gbraid || null, 2098 wbraid: merged.wbraid || null, 2099 fbclid: merged.fbclid || null, 2100 msclkid: merged.msclkid || null 2101 }; 2102} 2103 2104function classifyLeadSource(attrs) { 2105 // Paid Google 2106 if (attrs.gclid || attrs.gbraid || attrs.wbraid) return 'google_ads'; 2107 2108 // Paid social (your convention) 2109 if ((attrs.utm_medium || '').toLowerCase() === 'paid_social') return 'paid_social'; 2110 2111 // Catch-all social if you ever use utm_medium=social 2112 if ((attrs.utm_medium || '').toLowerCase() === 'social') return 'organic_social'; 2113 2114 return 'organic_or_other'; 2115} 2116 2117 2118function getGTMData() { 2119 2120 const attrs = getAttributionParams(); 2121 const lead_source = classifyLeadSource(attrs); 2122 const page_location = window.location.href; 2123 const page_path = window.location.pathname; 2124 2125 window.dataLayer = window.dataLayer || []; 2126 window.dataLayer.push({ 2127 event: 'formCompleted', 2128 form_name: "Enquire Now", 2129 page_path: page_path, 2130 page_location: page_location, 2131 submission_time: new Date().toISOString(), 2132 2133 // Attribution bundle 2134 lead_source: lead_source, 2135 utm_source: attrs.utm_source, 2136 utm_medium: attrs.utm_medium, 2137 utm_campaign: attrs.utm_campaign, 2138 utm_term: attrs.utm_term,
2139 utm_content: attrs.utm_content, 2140 gclid: attrs.gclid, 2141 gbraid: attrs.gbraid, 2142 wbraid: attrs.wbraid, 2143 fbclid: attrs.fbclid, 2144 msclkid: attrs.msclkid 2145 }); 2146 2147} 2148 2149 2150 2151function alertResultsPayment (sender) { 2152 2153 // loop through all fields and if none of the fields have the class is-payment-dropdown, then run the non-payment alertResults 2154 const fields = sender.getAllQuestions(); 2155 let hasPaymentDropdown = false; 2156 fields.forEach(field => { 2157 if (typeof field.jsonObj.class !== "undefined" && field.jsonObj.class === "is-payment-dropdown") { 2158 if (field.isVisible) { 2159 hasPaymentDropdown = true; 2160 } 2161 } 2162 }); 2163 if ( !hasPaymentDropdown ) { 2164 survey21.completedHtml = `<div class="surveyjs-thankyou"><h2 class="surveyjs-thankyou__title">Enquire Now</h2><p class="surveyjs-thankyou__message">Thank you. Your form has been submitted successfully.</p></div>`; 2165 survey21.showCompletedPage = true; 2166 return alertResults(sender); 2167 } 2168 2169 // Build ordered results (definition order, not "filled" order) 2170 const orderedData = getOrderedData(sender); 2171 const results = JSON.stringify(orderedData); 2172 2173 var turnstileToken = SJT.getTokenForSubmit(turnstileFormId); 2174 2175 // Get the values from hidden input fields 2176 const formid = document.getElementById('formid-21').value; 2177 const pageurl = document.getElementById('pageurl').value; 2178 const paymentElements = document.getElementById('paymentElements-21').value; 2179 2180 // Create a new form element dynamically 2181 const form = document.createElement("form"); 2182 form.method = "POST"; 2183 form.action = "/service/index/proxysjs/"; 2184 2185 // Function to add hidden input fields to the form 2186 function addHiddenField(name, value) { 2187 if (value !== undefined && value !== null) { 2188 let input = document.createElement("input"); 2189 input.type = "hidden"; 2190 input.name = name; 2191 input.value = value; 2192 form.appendChild(input); 2193 } 2194 } 2195 2196 // Append fields to the form 2197 addHiddenField("formid", formid); 2198 addHiddenField("pageurl", pageurl); 2199 addHiddenField("cf-turnstile-response", turnstileToken); 2200 addHiddenField("ajax", "1"); 2201 addHiddenField("data", results); 2202 addHiddenField("paymentElements", paymentElements); 2203 2204 // If stripeToken exists, append it 2205 const stripeTokenElement = document.getElementById("stripeToken"); 2206 if (stripeTokenElement) { 2207 addHiddenField("stripeToken", stripeTokenElement.value); 2208 } 2209 2210 getGTMData(); 2211 2212 // Show thank you message before submitting (since form.submit() navigates away) 2213 makeFormReadOnly(sender); 2214 2215 const surveyHolder = document.querySelector('#form-21').closest('.surveyjs-holder'); 2216 if (surveyHolder ) { 2217 surveyHolder.classList.add('surveyjs-submitted'); 2218 surveyHolder.innerHTML = '<h2 class="form-title">Enquire Now</h2><p class="extracontent1">Redirecting you to a secure payment page ...</p>'; 2219 } 2220 2221 // Append the form to the body and submit it (after showing message) 2222 document.body.appendChild(form); 2223 setTimeout(() => { 2224 form.submit(); 2225 }, 500); // Small delay to let user see the thank you message 2226 2227} 2228 2229function handleFormSubmissionResult(sender, surveyHolder, status, data, isNetworkError) { 2230 const container = document.getElementById('surveyContainer-21'); 2231 const completedPage = container && container.querySelector('.sd-completedpage'); 2232 2233 // Clear any previous error 2234 if (container) { 2235 const existingError = container.querySelector('.surveyjs-submit-error'); 2236 if (existingError) existingError.remove(); 2237 } 2238 2239 // Network-level failure 2240 if (isNetworkError) { 2241 if (surveyHolder) { 2242 surveyHolder.classList.remove('surveyjs-submitted'); 2243 } 2244 if (completedPage) { 2245 completedPage.style.display = 'none'; 2246 } 2247 const errEl = document.createElement('p'); 2248 errEl.className = 'surveyjs-submit-error'; 2249 errEl.setAttribute('role', 'alert'); 2250 errEl.style.color = '#b21f03'; 2251 errEl.style.marginTop = '1em'; 2252 errEl.textContent = 'Form error. Please check your connection and try again.'; 2253 if (container) { 2254 container.appendChild(errEl); 2255 } 2256 return; 2257 } 2258 2259 // Success from backend 2260 if (status === 200 && data === 'success') { 2261 // console.log('Success: ' + data); 2262 getGTMData(); 2263 setTimeout(() => { 2264 makeFormReadOnly(sender); 2265 }, 300); 2266 if (completedPage) { 2267 completedPage.style.display = ''; 2268 } 2269 return; 2270 } 2271 2272 // Turnstile / robot validation failure: 403 or Cloudflare challenge body 2273 const looksLikeTurnstileFailure = 2274 status === 403 || 2275 (data && (data.indexOf('Just a moment') !== -1 || data.indexOf('challenges.cloudflare.com') !== -1)); 2276 2277 if (surveyHolder) { 2278 surveyHolder.classList.remove('surveyjs-submitted'); 2279 } 2280 if (completedPage) { 2281 completedPage.style.display = 'none'; 2282 } 2283 2284 const errEl = document.createElement('p'); 2285 errEl.className = 'surveyjs-submit-error'; 2286 errEl.setAttribute('role', 'alert'); 2287 errEl.style.color = '#b21f03'; 2288 errEl.style.marginTop = '1em'; 2289 errEl.textContent = looksLikeTurnstileFailure 2290 ? 'Security check failed or expired. Please complete it again and resubmit.' 2291 : 'Form error. Please try again.'; 2292 2293 if (container) { 2294 container.appendChild(errEl); 2295 } 2296 2297 if (looksLikeTurnstileFailure) { 2298 SJT.resetWidget(turnstileFormId); 2299 SJT.syncCompleteButton(sender, turnstileFormId); 2300 } 2301} 2302 2303function alertResults (sender) { 2304 // Build ordered results (definition order, not "filled" order) 2305 const orderedData = getOrderedData(sender); 2306 const results = JSON.stringify(orderedData); 2307 2308 // Post these results to a url using javascript fetch or any other library 2309 // Create a new FormData object 2310 const formData = new FormData(); 2311 var turnstileToken = SJT.getTokenForSubmit(turnstileFormId); 2312 2313 // Get the values from the hidden input fields 2314 const formid = document.getElementById('formid-21').value; 2315 const pageurl = document.getElementById('pageurl').value; 2316 2317 // Get the paymentElements from the hidden input field 2318 const paymentElements = document.getElementById('paymentElements-21').value; 2319 2320 // If the form id stripeToken exists then add it to the form data 2321 if (document.getElementById('stripeToken')) { 2322 formData.append('stripeToken', document.getElementById('stripeToken').value); 2323 } 2324 2325 // Add your data as individual key-value pairs 2326 formData.append('formid', formid); 2327 formData.append('pageurl', pageurl); 2328 formData.append('cf-turnstile-response', turnstileToken); 2329 formData.append('ajax', 1); 2330 // IMPORTANT: results is already a JSON string; DO NOT JSON.stringify it again 2331 formData.append('data', results); 2332 formData.append('paymentElements', paymentElements); 2333 2334 // Add class to surveyjs-holder on successful submission 2335 const surveyHolder = document.querySelector('#form-21').closest('.surveyjs-holder'); 2336 if (surveyHolder) { 2337 surveyHolder.classList.add('surveyjs-submitted'); 2338 } 2339 2340 const yOffset = -280; 2341 const y = document.querySelector('#form-21').getBoundingClientRect().top + window.pageYOffset + yOffset; 2342 window.scrollTo({ top: y, behavior: 'smooth' }); 2343 2344 // Send the FormData object using fetch 2345 // Note: 403 here is often Cloudflare blocking the POST (e.g. when payload includes file upload data). 2346 // Add a WAF/Page Rule exception for /service/index/proxysjs/ in Cloudflare if submissions with files fail. 2347 fetch('/service/index/proxysjs/', { 2348 method: 'POST', 2349 body: formData, 2350 }) 2351 .then(response => { 2352 const status = response.status; 2353 return response.text().then(text => ({ status, text })); 2354 }) 2355 .then(({ status, text }) => { 2356 handleFormSubmissionResult(sender, surveyHolder, status, text, false); 2357 }) 2358 .catch(() => {
2359 handleFormSubmissionResult(sender, surveyHolder, 0, '', true); 2360 }); 2361} 2362 2363// Validate Turnstile before allowing survey completion 2364survey21.onCompleting.add((sender, options) => { 2365 var token = SJT.getTokenForSubmit(turnstileFormId); 2366 2367 if (!token) { 2368 options.allowComplete = false; 2369 SJT.showError(turnstileFormId, 'Please complete the security check below before submitting.'); 2370 SJT.syncCompleteButton(sender, turnstileFormId); 2371 return; 2372 } 2373 2374 SJT.clearError(turnstileFormId); 2375 2376 survey21.completedHtml = '<div class="surveyjs-thankyou"><h2 class="surveyjs-thankyou__title">Enquire Now</h2><p class="surveyjs-thankyou__message">Thank you. Your form has been submitted successfully.</p></div>'; 2377 }); 2378survey21.onAfterRenderSurvey.add(() => { 2379 SJT.syncCompleteButton(survey21, turnstileFormId); 2380}); 2381 survey21.onComplete.add(alertResults); 2382 2383 })(); 2384 2385 </script>
2385 2386</div> </div> 2387
2387<script nonce="WWpGbVlXTTBZVFUzWVdJNE16QXk=" src="/templates/oracle/js/home-min.js?ver=1404"></script>
2387 2388
2388<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"edb415346577442dba64a21004705484","r":1,"spa":2}' crossorigin="anonymous"></script>
2388 2389</body> 2390</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.