{"webLayers":[{"_id":"6373189237c7eba6ac1bfc10","date_filter":{"enabled":false,"from_date":null,"to_date":null},"trigger":{"include_pages":[{"url":"positivegrid.com/pages/consent","type":"contains"}],"exclude_pages":[{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"},{"url":"portal-staging.positivegrid.com","type":"contains"},{"url":"portal.positivegrid.com","type":"contains"}]},"smart_trigger":null,"device_target":{"type":"any"},"frequency":"always","uses_personalization":true,"data":"","variables_target":null,"page_vars":[]},{"_id":"6763864a164ad91f81dcc579","date_filter":{"enabled":false,"from_date":null,"to_date":null},"trigger":{"include_pages":[{"url":"staging.positivegrid.com","type":"contains"},{"url":"alto.positivegrid.com","type":"contains"}],"exclude_pages":[{"url":"/cart","type":"contains"},{"url":"/product","type":"contains"},{"url":"member-staging.positivegrid.com","type":"contains"},{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"},{"url":"portal-staging.positivegrid.com","type":"contains"},{"url":"portal.positivegrid.com","type":"contains"}]},"smart_trigger":null,"device_target":{"type":"any"},"frequency":"always","uses_personalization":true,"data":"","variables_target":null,"page_vars":[]},{"_id":"67a8989cb5f2a8b74f69f23c","date_filter":{"enabled":true,"from_date":null,"to_date":null},"trigger":{"include_pages":[{"url":"www.positivegrid.com","type":"contains"},{"url":"ca.positivegrid.com","type":"contains"},{"url":"au.positivegrid.com","type":"contains"},{"url":"jp.positivegrid.com","type":"contains"},{"url":"eu.positivegrid.com","type":"contains"},{"url":"uk.positivegrid.com","type":"contains"}],"exclude_pages":[{"url":"/cart","type":"contains"},{"url":"/pages/learn","type":"contains"},{"url":"welcome-to","type":"contains"},{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"},{"url":"portal-staging.positivegrid.com","type":"contains"},{"url":"portal.positivegrid.com","type":"contains"},{"url":"www.positivegrid.com/jp","type":"contains"}]},"smart_trigger":null,"device_target":{"type":"any"},"frequency":"always","uses_personalization":true,"data":"","variables_target":null,"page_vars":[]},{"_id":"6a27f68cb2171ef7f133fc60","date_filter":{"enabled":false,"from_date":null,"to_date":null},"trigger":{"include_pages":[{"url":"sandbox.positivegrid.com","type":"contains"}],"exclude_pages":[{"url":"member.positivegrid.com","type":"contains"},{"url":"member-staging.positivegrid.com","type":"contains"}]},"smart_trigger":null,"device_target":{"type":"any"},"frequency":"always","uses_personalization":true,"data":"","variables_target":null,"page_vars":[]},{"_id":"6a2900f964b425814775c73f","date_filter":{"enabled":false,"from_date":null,"to_date":null},"trigger":{"include_pages":[{"url":"www.positivegrid.com/jp","type":"contains"},{"url":"www.positivegrid.com/au","type":"contains"},{"url":"www.positivegrid.com/uk","type":"contains"},{"url":"www.positivegrid.com/ca","type":"contains"},{"url":"www.positivegrid.com/eu","type":"contains"}],"exclude_pages":[{"url":"member.positivegrid.com","type":"contains"},{"url":"/cart","type":"contains"}]},"smart_trigger":null,"device_target":{"type":"any"},"frequency":"always","uses_personalization":true,"data":"","variables_target":null,"page_vars":[]}],"experiments":[{"_id":"6982dfa31fec8e0ce09b976e","date_filter":{"enabled":true,"from_date":1769932800,"to_date":1771142399},"trigger":{"include_pages":[{"url":"https://member.positivegrid.com/signup","type":"contains"}],"exclude_pages":null},"trigger_event":{"type":"page_load"},"device_target":{"type":"any"},"frequency":"always","variables_target":null,"page_vars":[]}],"constantManagedTags":[{"uses_overlay":true,"type":"js","parametrized_definition":"(function() {\n    /*\n     jQuery v1.9.1 (c) 2005, 2012\n     jQuery Foundation, Inc. jquery.org/license.\n    */\n    var g = /\\[object (Boolean|Number|String|Function|Array|Date|RegExp)\\]/;\n\n    function h(a) {\n        return null == a ? String(a) : (a = g.exec(Object.prototype.toString.call(Object(a)))) ? a[1].toLowerCase() : \"object\"\n    }\n\n    function k(a, b) {\n        return Object.prototype.hasOwnProperty.call(Object(a), b)\n    }\n\n    function m(a) {\n        if (!a || \"object\" != h(a) || a.nodeType || a == a.window) return !1;\n        try {\n            if (a.constructor \u0026\u0026 !k(a, \"constructor\") \u0026\u0026 !k(a.constructor.prototype, \"isPrototypeOf\")) return !1\n        } catch (b) {\n            return !1\n        }\n        for (var c in a);\n        return void 0 === c || k(a, c)\n    };\n    /*\n     Copyright 2012 Google Inc. All rights reserved. */\n    function n(a, b, c) {\n        this.b = a;\n        this.f = b || function() {};\n        this.d = !1;\n        this.a = {};\n        this.c = [];\n        this.e = p(this);\n        r(this, a, !c);\n        var d = a.push,\n            e = this;\n        a.push = function() {\n            var b = [].slice.call(arguments, 0),\n                c = d.apply(a, b);\n            r(e, b);\n            return c\n        }\n    }\n    window.DataLayerHelper = n;\n    n.prototype.get = function(a) {\n        var b = this.a;\n        a = a.split(\".\");\n        for (var c = 0; c \u003c a.length; c++) {\n            if (void 0 === b[a[c]]) return;\n            b = b[a[c]]\n        }\n        return b\n    };\n    n.prototype.flatten = function() {\n        this.b.splice(0, this.b.length);\n        this.b[0] = {};\n        s(this.a, this.b[0])\n    };\n\n    function r(a, b, c) {\n        for (a.c.push.apply(a.c, b); !1 === a.d \u0026\u0026 0 \u003c a.c.length;) {\n            b = a.c.shift();\n            if (\"array\" == h(b)) a: {\n                var d = b,\n                    e = a.a;\n                if (\"string\" == h(d[0])) {\n                    for (var f = d[0].split(\".\"), u = f.pop(), d = d.slice(1), l = 0; l \u003c f.length; l++) {\n                        if (void 0 === e[f[l]]) break a;\n                        e = e[f[l]]\n                    }\n                    try {\n                        e[u].apply(e, d)\n                    } catch (v) {}\n                }\n            }\n            else if (\"function\" == typeof b) try {\n                    b.call(a.e)\n                } catch (w) {} else if (m(b))\n                    for (var q in b) s(t(q, b[q]), a.a);\n                else continue;\n            c || (a.d = !0, a.f(a.a, b), a.d = !1)\n        }\n    }\n\n    function p(a) {\n        return {\n            set: function(b, c) {\n                s(t(b, c), a.a)\n            },\n            get: function(b) {\n                return a.get(b)\n            }\n        }\n    }\n\n    function t(a, b) {\n        for (var c = {}, d = c, e = a.split(\".\"), f = 0; f \u003c e.length - 1; f++) d = d[e[f]] = {};\n        d[e[e.length - 1]] = b;\n        return c\n    }\n\n    function s(a, b) {\n        for (var c in a)\n            if (k(a, c)) {\n                var d = a[c];\n                \"array\" == h(d) ? (\"array\" == h(b[c]) || (b[c] = []), s(d, b[c])) : m(d) ? (m(b[c]) || (b[c] = {}), s(d, b[c])) : b[c] = d\n            }\n    };\n})();\n\nfunction process(model, m) {\n\tif (m.namespace == \"exponea\") {\n\t\t\n\t\t/*\n\t\t*\tMODIFY EVENT PROPERTIES\n\t\t*/\n\t\t\n\t\t// switch(m.event_name){\n\t\t// \tcase \"view_item\":\n\t\t// \t\tm.event_properties.price = parseFloat(price.split(\"€\")[0]);\n\t\t// \t\tbreak;\n\t\t// \tdefault:\n\t\t// \t\tbreak;\n\t\t// }\n\t\t\n\t\texponea.track(m.event_name,m.event_properties);\n\t}\n}\n\nnew DataLayerHelper(dataLayer, process, true);","trigger":{"include_pages":[{"url":"https://staging.positivegrid.com","type":"contains"}],"exclude_pages":null},"_id":"68bea20dfef3ea7d3c725853"},{"uses_overlay":false,"type":"js","parametrized_definition":"(function() {\n    /*\n     jQuery v1.9.1 (c) 2005, 2012\n     jQuery Foundation, Inc. jquery.org/license.\n    */\n    var g = /\\[object (Boolean|Number|String|Function|Array|Date|RegExp)\\]/;\n\n    function h(a) {\n        return null == a ? String(a) : (a = g.exec(Object.prototype.toString.call(Object(a)))) ? a[1].toLowerCase() : \"object\"\n    }\n\n    function k(a, b) {\n        return Object.prototype.hasOwnProperty.call(Object(a), b)\n    }\n\n    function m(a) {\n        if (!a || \"object\" != h(a) || a.nodeType || a == a.window) return !1;\n        try {\n            if (a.constructor \u0026\u0026 !k(a, \"constructor\") \u0026\u0026 !k(a.constructor.prototype, \"isPrototypeOf\")) return !1\n        } catch (b) {\n            return !1\n        }\n        for (var c in a);\n        return void 0 === c || k(a, c)\n    };\n    /*\n     Copyright 2012 Google Inc. All rights reserved. */\n    function n(a, b, c) {\n        this.b = a;\n        this.f = b || function() {};\n        this.d = !1;\n        this.a = {};\n        this.c = [];\n        this.e = p(this);\n        r(this, a, !c);\n        var d = a.push,\n            e = this;\n        a.push = function() {\n            var b = [].slice.call(arguments, 0),\n                c = d.apply(a, b);\n            r(e, b);\n            return c\n        }\n    }\n    window.DataLayerHelper = n;\n    n.prototype.get = function(a) {\n        var b = this.a;\n        a = a.split(\".\");\n        for (var c = 0; c \u003c a.length; c++) {\n            if (void 0 === b[a[c]]) return;\n            b = b[a[c]]\n        }\n        return b\n    };\n    n.prototype.flatten = function() {\n        this.b.splice(0, this.b.length);\n        this.b[0] = {};\n        s(this.a, this.b[0])\n    };\n\n    function r(a, b, c) {\n        for (a.c.push.apply(a.c, b); !1 === a.d \u0026\u0026 0 \u003c a.c.length;) {\n            b = a.c.shift();\n            if (\"array\" == h(b)) a: {\n                var d = b,\n                    e = a.a;\n                if (\"string\" == h(d[0])) {\n                    for (var f = d[0].split(\".\"), u = f.pop(), d = d.slice(1), l = 0; l \u003c f.length; l++) {\n                        if (void 0 === e[f[l]]) break a;\n                        e = e[f[l]]\n                    }\n                    try {\n                        e[u].apply(e, d)\n                    } catch (v) {}\n                }\n            }\n            else if (\"function\" == typeof b) try {\n                    b.call(a.e)\n                } catch (w) {} else if (m(b))\n                    for (var q in b) s(t(q, b[q]), a.a);\n                else continue;\n            c || (a.d = !0, a.f(a.a, b), a.d = !1)\n        }\n    }\n\n    function p(a) {\n        return {\n            set: function(b, c) {\n                s(t(b, c), a.a)\n            },\n            get: function(b) {\n                return a.get(b)\n            }\n        }\n    }\n\n    function t(a, b) {\n        for (var c = {}, d = c, e = a.split(\".\"), f = 0; f \u003c e.length - 1; f++) d = d[e[f]] = {};\n        d[e[e.length - 1]] = b;\n        return c\n    }\n\n    function s(a, b) {\n        for (var c in a)\n            if (k(a, c)) {\n                var d = a[c];\n                \"array\" == h(d) ? (\"array\" == h(b[c]) || (b[c] = []), s(d, b[c])) : m(d) ? (m(b[c]) || (b[c] = {}), s(d, b[c])) : b[c] = d\n            }\n    };\n})();\n\nfunction process(model, m) {\n\tif (m.namespace == \"exponea\") {\n\t\t\n\t\t/*\n\t\t*\tMODIFY EVENT PROPERTIES\n\t\t*/\n\t\t\n\t\t// switch(m.event_name){\n\t\t// \tcase \"view_item\":\n\t\t// \t\tm.event_properties.price = parseFloat(price.split(\"€\")[0]);\n\t\t// \t\tbreak;\n\t\t// \tdefault:\n\t\t// \t\tbreak;\n\t\t// }\n\t\t\n\t\texponea.track(m.event_name,m.event_properties);\n\t}\n}\n\nnew DataLayerHelper(dataLayer, process, true);","trigger":{"include_pages":[{"type":"any"}],"exclude_pages":null},"_id":"60a522dc949955da3f18815d"},{"uses_overlay":false,"type":"html","parametrized_definition":"    \u003cscript\u003e\n        window.interdeal = {\n          sitekey: 'b6b98c0c0aee228b79b70bf877616ed5',\n          Position: 'Left',\n          Menulang: 'EN',\n          domains: { js: 'https://cdn.equalweb.com/', acc: 'https://access.equalweb.com/' },\n          btnStyle: {\n            vPosition: ['80%', null],\n            scale: ['0.6', '0.6'],\n            color: { main: '#1876c9', second: '' },\n            icon: { type: 7, shape: 'semicircle', outline: false },\n          },\n        };\n        (function (doc, head, body) {\n          var coreCall = doc.createElement('script');\n          coreCall.src = 'https://cdn.equalweb.com/core/4.4.0/accessibility.js';\n          coreCall.defer = true;\n          coreCall.integrity =\n            'sha512-3lGJBcuai1J0rGJHJj4e4lYOzm7K08oEHsg1Llt7x24OOsa/Ca0wwbSi9HhWUn92FKN3fylaq9xmIKVZnUsT3Q==';\n          coreCall.crossOrigin = 'anonymous';\n          coreCall.setAttribute('data-cfasync', true);\n          body ? body.appendChild(coreCall) : head.appendChild(coreCall);\n        })(document, document.head, document.body);\n    \u003c/script\u003e","trigger":{"include_pages":[{"url":"https://www.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"63633379a8d119d114cbbe69"},{"uses_overlay":false,"type":"html","parametrized_definition":"    \u003cscript\u003e\n        window.interdeal = {\n          sitekey: '20b5841daa431c368483aff277a11ee9',\n          Position: 'Left',\n          Menulang: 'EN',\n          domains: { js: 'https://cdn.equalweb.com/', acc: 'https://access.equalweb.com/' },\n          btnStyle: {\n            vPosition: ['80%', null],\n            scale: ['0.8', '0.8'],\n            color: { main: '#1876c9', second: '' },\n            icon: { type: 7, shape: 'semicircle' },\n          },\n        };\n        (function (doc, head, body) {\n          var coreCall = doc.createElement('script');\n          coreCall.src = 'https://cdn.equalweb.com/core/4.3.7/accessibility.js';\n          coreCall.defer = true;\n          coreCall.integrity =\n            'sha512-hGa5HZtFkT1M7+tUDtU/cbw6AG0ORz3oblztCoTZ/z2qPyr7dgwH3zoT8qpgj21MgcRsMFLD6NNKePGvVks3Ig==';\n          coreCall.crossOrigin = 'anonymous';\n          coreCall.setAttribute('data-cfasync', true);\n          body ? body.appendChild(coreCall) : head.appendChild(coreCall);\n        })(document, document.head, document.body);\n    \u003c/script\u003e","trigger":{"include_pages":[{"url":"https://ca.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"636333fc2a96f5a282d90abf"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/Z5zAQbeXyRhhUOAsCNpwrpAngMqs653PnHCgw4zX/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://www.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d68cae3bedb420e219e4"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/ZfIQFtE7Ndr2nmXq45pVAUoOmGZNhnkAHqTJjRcr/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://ca.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d6d03830e11a0d4f7ab7"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/NYod0wFzd6SoMbIEokKF5XX001kizqyIXwqtz5e1/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://uk.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d6f4ae3bedb420e219f0"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/EIkJRu8VqOWO2dFjEXwJRtnh2DLlddR1gwoq3l8y/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://eu.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d71dd96e4e0e26e27510"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/srbpuhUbHSnIrzkDbrbDO27N3MnhrwRpiA7crCEL/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://au.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d7433b2079ae5bb8b376"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript type=\"text/javascript\"\u003e\n\t(function e(){var e=document.createElement(\"script\");e.type=\"text/javascript\",e.async=true,e.src=\"//staticw2.yotpo.com/uqKiyKCjesuMSNcxrtxrgYKYR3jY2Eycj7nUdtt5/widget.js\";var t=document.getElementsByTagName(\"script\")[0];t.parentNode.insertBefore(e,t)})();\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://jp.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6369d7673bb53dbb302d78ed"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://ca.positivegrid.com --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:3121075,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://ca.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a6fba97522285c5910f6"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://au.positivegrid.com/ --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:3198326,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://au.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a735a97522285c5910fe"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://eu.positivegrid.com/ --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:3198325,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://eu.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a75abb76f698a3e010c4"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://uk.positivegrid.com/ --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:3198319,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://uk.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a77cd0ee50464f31d80b"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://jp.positivegrid.com/ --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:3198327,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://jp.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a79e5657e1a41aca423e"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Hotjar Tracking Code for https://www.positivegrid.com/ --\u003e\n\u003cscript\u003e\n    (function(h,o,t,j,a,r){\n        h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};\n        h._hjSettings={hjid:985800,hjsv:6};\n        a=o.getElementsByTagName('head')[0];\n        r=o.createElement('script');r.async=1;\n        r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;\n        a.appendChild(r);\n    })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://www.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"6371a7c814dcd730a7792fcd"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003cscript\u003efunction loadScript(a){var b=document.getElementsByTagName(\"head\")[0],c=document.createElement(\"script\");c.type=\"text/javascript\",c.src=\"https://tracker.metricool.com/resources/be.js\",c.onreadystatechange=a,c.onload=a,b.appendChild(c)}loadScript(function(){beTracker.t({hash:\"9e0f767623d7f81e6d6825fbe8abd555\"})});\u003c/script\u003e","trigger":{"include_pages":[{"url":"www.positivegrid.com/","type":"contains"}],"exclude_pages":null},"_id":"64250a34f1ceb725cf3c7300"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Accessibility Code for \"uk.positivegrid.com\" --\u003e\n\u003cscript\u003e\nwindow.interdeal = {\n    \"sitekey\": \"2669c1d740eef0b143618b9dbf811abe\",\n    \"Position\": \"Left\",\n    \"Menulang\": \"EN-GB\",\n    \"domains\": {\n        \"js\": \"https://cdn.equalweb.com/\",\n        \"acc\": \"https://access.equalweb.com/\"\n    },\n    \"btnStyle\": {\n        \"vPosition\": [\n            \"80%\",\n            null\n        ],\n        \"scale\": [\n            \"0.8\",\n            \"0.8\"\n        ],\n        \"icon\": {\n            \"type\": 7,\n            \"shape\": \"semicircle\"\n        }\n    }\n};\n(function(doc, head, body){\n\tvar coreCall             = doc.createElement('script');\n\tcoreCall.src             = 'https://cdn.equalweb.com/core/4.5.8/accessibility.js';\n\tcoreCall.defer           = true;\n\tcoreCall.integrity       = 'sha512-edRZXolhkUWHM/uu0oiEu0tD39SPOhnl5a2KM+62YWIfb4M5oSMjvyl2NPXtGq8McfJl88bKtaxljjViGqQXtA==';\n\tcoreCall.crossOrigin     = 'anonymous';\n\tcoreCall.setAttribute('data-cfasync', true );\n\tbody? body.appendChild(coreCall) : head.appendChild(coreCall);\n})(document, document.head, document.body);\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://uk.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"651e5bc7dfcc51a421b7a874"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Accessibility Code for \"eu.positivegrid.com\" --\u003e\n\u003cscript\u003e\nwindow.interdeal = {\n    \"sitekey\": \"84c151a84c64ab87a7701825268b3475\",\n    \"Position\": \"Left\",\n    \"Menulang\": \"EN-GB\",\n    \"domains\": {\n        \"js\": \"https://cdn.equalweb.com/\",\n        \"acc\": \"https://access.equalweb.com/\"\n    },\n    \"btnStyle\": {\n        \"vPosition\": [\n            \"80%\",\n            null\n        ],\n        \"scale\": [\n            \"0.8\",\n            \"0.8\"\n        ],\n        \"icon\": {\n            \"type\": 7,\n            \"shape\": \"semicircle\"\n        }\n    }\n};\n(function(doc, head, body){\n\tvar coreCall             = doc.createElement('script');\n\tcoreCall.src             = 'https://cdn.equalweb.com/core/4.5.8/accessibility.js';\n\tcoreCall.defer           = true;\n\tcoreCall.integrity       = 'sha512-edRZXolhkUWHM/uu0oiEu0tD39SPOhnl5a2KM+62YWIfb4M5oSMjvyl2NPXtGq8McfJl88bKtaxljjViGqQXtA==';\n\tcoreCall.crossOrigin     = 'anonymous';\n\tcoreCall.setAttribute('data-cfasync', true );\n\tbody? body.appendChild(coreCall) : head.appendChild(coreCall);\n})(document, document.head, document.body);\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://eu.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"651e5c1ec19f9497715a7125"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Accessibility Code for \"jp.positivegrid.com\" --\u003e\n\u003cscript\u003e\nwindow.interdeal = {\n    \"sitekey\": \"22ffc2ad6da8fc15be4ab2d7232c25c0\",\n    \"Position\": \"Left\",\n    \"Menulang\": \"JA\",\n    \"domains\": {\n        \"js\": \"https://cdn.equalweb.com/\",\n        \"acc\": \"https://access.equalweb.com/\"\n    },\n    \"btnStyle\": {\n        \"vPosition\": [\n            \"80%\",\n            null\n        ],\n        \"scale\": [\n            \"0.8\",\n            \"0.8\"\n        ],\n        \"icon\": {\n            \"type\": 7,\n            \"shape\": \"semicircle\"\n        }\n    }\n};\n(function(doc, head, body){\n\tvar coreCall             = doc.createElement('script');\n\tcoreCall.src             = 'https://cdn.equalweb.com/core/4.5.8/accessibility.js';\n\tcoreCall.defer           = true;\n\tcoreCall.integrity       = 'sha512-edRZXolhkUWHM/uu0oiEu0tD39SPOhnl5a2KM+62YWIfb4M5oSMjvyl2NPXtGq8McfJl88bKtaxljjViGqQXtA==';\n\tcoreCall.crossOrigin     = 'anonymous';\n\tcoreCall.setAttribute('data-cfasync', true );\n\tbody? body.appendChild(coreCall) : head.appendChild(coreCall);\n})(document, document.head, document.body);\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://jp.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"651e5c531710e9c16c6ea91d"},{"uses_overlay":false,"type":"html","parametrized_definition":"\u003c!-- Accessibility Code for \"au.positivegrid.com\" --\u003e\n\u003cscript\u003e\nwindow.interdeal = {\n    \"sitekey\": \"b7410ba2f8c206ae9281123703055ab2\",\n    \"Position\": \"Left\",\n    \"Menulang\": \"EN-GB\",\n    \"domains\": {\n        \"js\": \"https://cdn.equalweb.com/\",\n        \"acc\": \"https://access.equalweb.com/\"\n    },\n    \"btnStyle\": {\n        \"vPosition\": [\n            \"80%\",\n            null\n        ],\n        \"scale\": [\n            \"0.8\",\n            \"0.8\"\n        ],\n        \"color\": {\n            \"main\": \"#1876c9\",\n            \"second\": \"\"\n        },\n        \"icon\": {\n            \"type\": 7,\n            \"shape\": \"semicircle\"\n        }\n    }\n};\n(function(doc, head, body){\n\tvar coreCall             = doc.createElement('script');\n\tcoreCall.src             = 'https://cdn.equalweb.com/core/4.5.8/accessibility.js';\n\tcoreCall.defer           = true;\n\tcoreCall.integrity       = 'sha512-edRZXolhkUWHM/uu0oiEu0tD39SPOhnl5a2KM+62YWIfb4M5oSMjvyl2NPXtGq8McfJl88bKtaxljjViGqQXtA==';\n\tcoreCall.crossOrigin     = 'anonymous';\n\tcoreCall.setAttribute('data-cfasync', true );\n\tbody? body.appendChild(coreCall) : head.appendChild(coreCall);\n})(document, document.head, document.body);\n\u003c/script\u003e","trigger":{"include_pages":[{"url":"https://au.positivegrid.com/*","type":"exact"}],"exclude_pages":null},"_id":"651e5c8715d2854c976bebc1"},{"uses_overlay":false,"type":"js","parametrized_definition":"/*\nhttps://positivegrid.atlassian.net/browse/OSK-945\nhttps://app.us1.exponea.com/p/positive-grid-dev/data/managed-tags/6527a89c4843f27f968b438a/edit\n\n20240418\n  - https://positivegrid.atlassian.net/jira/software/projects/OSK/boards/3?selectedIssue=OSK-1098\n@author milkmidi.liao@gmail.com / clay.kao@positivegrid.com\n*/\nfunction createLogger(moduleName, style) {\n  return (...args) =\u003e {\n    console.log.apply(console, [`%c ${moduleName} `, style, ...args]);\n  };\n}\n\n/**\n * Detects if the PGModel is ready by polling for a specific condition.\n *\n * @return {Promise} A promise that resolves when the PGModel is ready, and rejects\n * if it takes longer than 3 seconds.\n */\nconst detectPGModelReady = () =\u003e {\n  return new Promise((resolve, reject) =\u003e {\n    let executeCount = 0;\n    const timeId = setInterval(() =\u003e {\n      if (executeCount \u003e= 30) {\n        clearInterval(timeId);\n        reject(new Error('PGModel is not ready'));\n        return;\n      }\n      if (window.PGModel \u0026\u0026 window.PGModel.alertPGSitePopup) {\n        clearInterval(timeId);\n        resolve();\n      }\n      executeCount += 1;\n    }, 100);\n  });\n};\n\n// 只要有箱子的都算硬體\n// 目前 cart 的product_type : 'Physical' | 'Digital' | 'Others' | 'Gift Cards';\n// 配件的 product_type : 'Others'\nconst isProductWithBoxes = (productType) =\u003e ['Physical', 'Others'].includes(productType);\n\n/**\n * Detects if the cart has another hardware product based on the SKU and limit quantity.\n *\n * @param {array} cartItems - The array of cart items(Shopify)\n * @param {array} skus - The SKU of the product to search for in the cart\n * @param {number} limitQuantity - The limit quantity to compare against\n * @return {boolean} Whether the cart has another hardware product or if the quantity is invalid\n */\nconst cartHasOtherHardware = (options) =\u003e {\n  const {\n    cartItems = window.PG_DATA.cart.items,\n    skus,\n    limitQuantity = Number.MAX_VALUE,\n    excludeOtherSkus = [],\n  } = options;\n  const findProductInCart = cartItems.find((item) =\u003e skus.includes(item.sku));\n  if (!findProductInCart) {\n    // 找不到商品就不用處理後續了。\n    return false;\n  }\n  // find Other Products\n  const restLineItem = cartItems.filter((item) =\u003e !skus.includes(item.sku));\n  const hasOtherHardwareProduct = restLineItem.some((item) =\u003e {\n    if (excludeOtherSkus.includes(item.sku)) {\n      return false;\n    }\n    return isProductWithBoxes(item.product_type);\n  }); // 是否有其他的硬體商品\n  const quantityInvalidate = findProductInCart.quantity \u003e= limitQuantity; // 數量是否超過\n  return hasOtherHardwareProduct || quantityInvalidate;\n};\n\n/**\n * Detects if the cart contains any of the specified SKUs.\n *\n * @param {cartItems} cartItems - The array of cart items(Shopify)\n * @param {Array} skus - The array of SKUs to check for in the cart\n * @return {boolean} true if the cart contains any of the specified SKUs, false otherwise\n */\nconst detectCartIncludesSkus = (cartItems, skus) =\u003e cartItems.some((item) =\u003e skus.includes(item.sku));\n\n/**\n * Finds the first matched text based on the conditions of the rules array.\n *\n * @param {Array} rules - The array of rules to be evaluated.\n * @return {string|null} The matched text or null if no match is found.\n */\nconst findFirstMatchedRule = (rules) =\u003e rules.find((rule) =\u003e rule.condition());\n\n/**\n * Returns a promisified version of the input function that resolves if the function\n * returns a truthy value and rejects with the provided error message if the function\n * returns a falsy value.\n *\n * @param {function} fn - The function to be promisified\n * @param {string} errorMessage - The error message to be used when the function returns falsy\n * @return {function} - A promisified version of the input function\n */\nconst promisifyUntil = (fn, errorMessage = '') =\u003e {\n  return (...args) =\u003e {\n    return new Promise((resolve, reject) =\u003e {\n      const result = fn(...args);\n      if (result) {\n        resolve(result);\n      } else {\n        reject(new Error(errorMessage));\n      }\n    });\n  };\n};\n\nconst logger = createLogger(\n  'exponea Popup Alert in cart page - https://app.us1.exponea.com/p/positive-grid-dev/data/managed-tags/65d58d5ada6e2274c08b93ed/edit',\n  'background:#fed501;',\n);\nconst promisifyfindFirstMatchedRule = promisifyUntil(findFirstMatchedRule);\n\nconst PRODUCT_SKU = {\n  SPARK_LIVE: 'HW0109LV-B',\n  SPARK_BATTERY: 'HW0518',\n  SPARK_CONTROL_X: 'HW0507X',\n  SPARK_CAB: 'HW0109CAB-B',\n};\n\nconst CUSTOM_GRILLES = [\n  'HWKF0501', // Personalized Spark Grille\n  'HWKF0502', // Personalized Spark MINI Grille\n];\n\nconst B2B_PRODUCTS = [\n  'HW0517_B2B',\n  'HW0502_B2B',\n  'HW0518_B2B',\n  'HW0507X_B2B',\n  'HW0507_B2B',\n  'HW0205_B2B',\n  'HW0109LV-B_B2B',\n  'HW0109CAB-B_B2B',\n  'HW0109GO-B_B2B',\n  'HW0109GO-PS_B2B',\n  'HW0109MI-B-5_B2B',\n  'HW0109MI-PS-5_B2B',\n  'HW0109_B2B',\n  'HW0109PS_B2B',\n];\nconst Spark2 = [\n  'HW0109-GEN2',\n  'HW0109-GEN2-1',\n  'HW0109-GEN2-2',\n  'HW0109-GEN2-3',\n  'HW0109-GEN2-U',\n  'HW0109-GEN2-U-1',\n  'HW0109-GEN2-U-2',\n  'HW0109-GEN2-U-3',\n  'HW0109-GEN2-PS',\n  'HW0109-GEN2-PS-1',\n  'HW0109-GEN2-PS-2',\n  'HW0109-GEN2-PS-3',\n  'HW0109-GEN2-PSU',\n  'HW0109-GEN2-PSU-1',\n  'HW0109-GEN2-PSU-2',\n  'HW0109-GEN2-PSU-3',\n];\nconst PRE_ORDER_PRODUCTS = [];\n\nconst cartItems = window.PG_DATA.cart.items;\n\nconst CART_VALIDATION_RULES = [\n  // OSK-1140: https://positivegrid.atlassian.net/browse/OSK-1140\n  {\n    name: 'B2B + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: B2B_PRODUCTS,\n      }),\n    text: 'Your cart contains items not eligible for the School of Rock program. Please remove any items that don’t include ‘SOR’ in the product name so your coupon code can be applied.',\n  },\n  {\n    // OSK-1098\n    name: 'Carts containing Spark CAB or Spark LIVE + any hardware not on pre-order',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: [PRODUCT_SKU.SPARK_CAB, PRODUCT_SKU.SPARK_LIVE],\n        excludeOtherSkus: PRE_ORDER_PRODUCTS,\n      }),\n    text: 'Your cart contains one or more Spark CAB or Spark LIVE. Please note that each Spark CAB or Spark LIVE unit will ship separately due to their size.',\n  },\n  /*\n  {\n    // OSK-1098\n    // OSK-1241\n    name: `Cart containing Spark Control X`,\n    condition: () =\u003e detectCartIncludesSkus(cartItems, PRE_ORDER_PRODUCTS),\n    text: 'Your cart contains one or more items that are on pre-order. Items on pre-order will ship as soon as they become available. In-stock items will ship immediately. If your order contains more than one Spark LIVE, Spark CAB or a mix of both, please note that each unit will ship separately due to their size.',\n  },\n  */\n  {\n    name: `Cart containing Spark CAB and Custom grille`,\n    condition: () =\u003e\n      detectCartIncludesSkus(cartItems, [PRODUCT_SKU.SPARK_CAB]) \u0026\u0026 detectCartIncludesSkus(cartItems, CUSTOM_GRILLES),\n    text: 'Your cart contains one or more Spark CABs and a personalized amp grille. Please note that the personalized grilles will ship separately from all the items in your order and each Spark CAB unit will ship separately due to their size.',\n  },\n  {\n    name: 'Spark CAB + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: [PRODUCT_SKU.SPARK_CAB],\n        limitQuantity: 2,\n      }),\n    text: 'Your cart contains one or more Spark CABs. Please note that each Spark CAB unit will ship separately due to their size.',\n  },\n  {\n    name: 'Custom grille + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: CUSTOM_GRILLES,\n      }),\n    text: 'Customized grille will ship separately from the rest of the order.',\n  },\n  // 20241219 OSK-1460 hide pre-order popup\n  /*\n  {\n    // Spark2 pre-order\n    name: 'Spark2 + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: Spark2,\n      }),\n    text: 'Your cart contains one or more items that are on pre-order. Items on pre-order will ship as soon as they become available. In-stock items will ship immediately.  If your order contains more than one Spark LIVE, Spark CAB or a mix of both, please note that each unit will ship separately due to their size.',\n  },\n  */\n];\n\nPromise.resolve()\n  .then(detectPGModelReady)\n  .then(() =\u003e logger('detectPGModelReady'))\n  .then(() =\u003e promisifyfindFirstMatchedRule(CART_VALIDATION_RULES)) // Find the first matched rule\n  .then((rule) =\u003e {\n    logger(`detect:${rule.name}`);\n    return window.PGModel.alertPGSitePopup({\n      content: rule.text,\n      acceptCTAText: 'CONTINUE',\n    });\n  })\n  .catch((err) =\u003e {\n    console.log('[OSK-945, OSK-1140] not fitting rule');\n  });\n\nlogger('start');\n","trigger":{"include_pages":[{"url":"https://www.positivegrid.com/cart","type":"exact"},{"url":"https://eu.positivegrid.com/cart","type":"exact"},{"url":"https://ca.positivegrid.com/cart","type":"exact"},{"url":"https://uk.positivegrid.com/cart","type":"exact"},{"url":"https://au.positivegrid.com/cart","type":"exact"}],"exclude_pages":[{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"},{"url":"portal-staging.positivegrid.com","type":"contains"},{"url":"portal.positivegrid.com","type":"contains"}]},"_id":"65d58d5ada6e2274c08b93ed"},{"uses_overlay":false,"type":"js","parametrized_definition":"/*\nhttps://positivegrid.atlassian.net/browse/OSK-945\nhttps://app.us1.exponea.com/p/positive-grid-dev/data/managed-tags/6527a89c4843f27f968b438a/edit\n\n20240418\n  - https://positivegrid.atlassian.net/jira/software/projects/OSK/boards/3?selectedIssue=OSK-1098\n@author milkmidi.liao@gmail.com / clay.kao@positivegrid.com\n*/\nfunction createLogger(moduleName, style) {\n  return (...args) =\u003e {\n    console.log.apply(console, [`%c ${moduleName} `, style, ...args]);\n  };\n}\n\n/**\n * Detects if the PGModel is ready by polling for a specific condition.\n *\n * @return {Promise} A promise that resolves when the PGModel is ready, and rejects\n * if it takes longer than 3 seconds.\n */\nconst detectPGModelReady = () =\u003e {\n  return new Promise((resolve, reject) =\u003e {\n    let executeCount = 0;\n    const timeId = setInterval(() =\u003e {\n      if (executeCount \u003e= 30) {\n        clearInterval(timeId);\n        reject(new Error('PGModel is not ready'));\n        return;\n      }\n      if (window.PGModel \u0026\u0026 window.PGModel.alertPGSitePopup) {\n        clearInterval(timeId);\n        resolve();\n      }\n      executeCount += 1;\n    }, 100);\n  });\n};\n\n// 只要有箱子的都算硬體\n// 目前 cart 的product_type : 'Physical' | 'Digital' | 'Others' | 'Gift Cards';\n// 配件的 product_type : 'Others'\nconst isProductWithBoxes = (productType) =\u003e ['Physical', 'Others'].includes(productType);\n\n/**\n * Detects if the cart has another hardware product based on the SKU and limit quantity.\n *\n * @param {array} cartItems - The array of cart items(Shopify)\n * @param {array} skus - The SKU of the product to search for in the cart\n * @param {number} limitQuantity - The limit quantity to compare against\n * @return {boolean} Whether the cart has another hardware product or if the quantity is invalid\n */\nconst cartHasOtherHardware = (options) =\u003e {\n  const {\n    cartItems = window.PG_DATA.cart.items,\n    skus,\n    limitQuantity = Number.MAX_VALUE,\n    excludeOtherSkus = [],\n  } = options;\n  const findProductInCart = cartItems.find((item) =\u003e skus.includes(item.sku));\n  if (!findProductInCart) {\n    // 找不到商品就不用處理後續了。\n    return false;\n  }\n  // find Other Products\n  const restLineItem = cartItems.filter((item) =\u003e !skus.includes(item.sku));\n  const hasOtherHardwareProduct = restLineItem.some((item) =\u003e {\n    if (excludeOtherSkus.includes(item.sku)) {\n      return false;\n    }\n    return isProductWithBoxes(item.product_type);\n  }); // 是否有其他的硬體商品\n  const quantityInvalidate = findProductInCart.quantity \u003e= limitQuantity; // 數量是否超過\n  return hasOtherHardwareProduct || quantityInvalidate;\n};\n\n/**\n * Detects if the cart contains any of the specified SKUs.\n *\n * @param {cartItems} cartItems - The array of cart items(Shopify)\n * @param {Array} skus - The array of SKUs to check for in the cart\n * @return {boolean} true if the cart contains any of the specified SKUs, false otherwise\n */\nconst detectCartIncludesSkus = (cartItems, skus) =\u003e cartItems.some((item) =\u003e skus.includes(item.sku));\n\n/**\n * Finds the first matched text based on the conditions of the rules array.\n *\n * @param {Array} rules - The array of rules to be evaluated.\n * @return {string|null} The matched text or null if no match is found.\n */\nconst findFirstMatchedRule = (rules) =\u003e rules.find((rule) =\u003e rule.condition());\n\n/**\n * Returns a promisified version of the input function that resolves if the function\n * returns a truthy value and rejects with the provided error message if the function\n * returns a falsy value.\n *\n * @param {function} fn - The function to be promisified\n * @param {string} errorMessage - The error message to be used when the function returns falsy\n * @return {function} - A promisified version of the input function\n */\nconst promisifyUntil = (fn, errorMessage = '') =\u003e {\n  return (...args) =\u003e {\n    return new Promise((resolve, reject) =\u003e {\n      const result = fn(...args);\n      if (result) {\n        resolve(result);\n      } else {\n        reject(new Error(errorMessage));\n      }\n    });\n  };\n};\n\nconst logger = createLogger(\n  'exponea Popup Alert in cart page - https://app.us1.exponea.com/p/positive-grid-dev/data/managed-tags/65d58d5ada6e2274c08b93ed/edit',\n  'background:#fed501;',\n);\nconst promisifyfindFirstMatchedRule = promisifyUntil(findFirstMatchedRule);\n\nconst PRODUCT_SKU = {\n  SPARK_LIVE: 'HW0109LV-B',\n  SPARK_BATTERY: 'HW0518',\n  SPARK_CONTROL_X: 'HW0507X',\n  SPARK_CAB: 'HW0109CAB-B',\n};\n\nconst CUSTOM_GRILLES = [\n  'HWKF0501', // Personalized Spark Grille\n  'HWKF0502', // Personalized Spark MINI Grille\n];\n\nconst B2B_PRODUCTS = [\n  'HW0517_B2B',\n  'HW0502_B2B',\n  'HW0518_B2B',\n  'HW0507X_B2B',\n  'HW0507_B2B',\n  'HW0205_B2B',\n  'HW0109LV-B_B2B',\n  'HW0109CAB-B_B2B',\n  'HW0109GO-B_B2B',\n  'HW0109GO-PS_B2B',\n  'HW0109MI-B-5_B2B',\n  'HW0109MI-PS-5_B2B',\n  'HW0109_B2B',\n  'HW0109PS_B2B',\n];\nconst Spark2 = [\n  'HW0109-GEN2',\n  'HW0109-GEN2-1',\n  'HW0109-GEN2-2',\n  'HW0109-GEN2-3',\n  'HW0109-GEN2-U',\n  'HW0109-GEN2-U-1',\n  'HW0109-GEN2-U-2',\n  'HW0109-GEN2-U-3',\n  'HW0109-GEN2-PS',\n  'HW0109-GEN2-PS-1',\n  'HW0109-GEN2-PS-2',\n  'HW0109-GEN2-PS-3',\n  'HW0109-GEN2-PSU',\n  'HW0109-GEN2-PSU-1',\n  'HW0109-GEN2-PSU-2',\n  'HW0109-GEN2-PSU-3',\n];\nconst PRE_ORDER_PRODUCTS = [];\n\nconst cartItems = window.PG_DATA.cart.items;\n\nconst CART_VALIDATION_RULES = [\n  // OSK-1140: https://positivegrid.atlassian.net/browse/OSK-1140\n  {\n    name: 'B2B + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: B2B_PRODUCTS,\n      }),\n    text: 'Your cart contains items not eligible for the School of Rock program. Please remove any items that don’t include ‘SOR’ in the product name so your coupon code can be applied.',\n  },\n  {\n    // OSK-1098\n    name: 'Carts containing Spark CAB or Spark LIVE + any hardware not on pre-order',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: [PRODUCT_SKU.SPARK_CAB, PRODUCT_SKU.SPARK_LIVE],\n        excludeOtherSkus: PRE_ORDER_PRODUCTS,\n      }),\n    text: 'Your cart contains one or more Spark CAB or Spark LIVE. Please note that each Spark CAB or Spark LIVE unit will ship separately due to their size.',\n  },\n  /*\n  {\n    // OSK-1098\n    // OSK-1241\n    name: `Cart containing Spark Control X`,\n    condition: () =\u003e detectCartIncludesSkus(cartItems, PRE_ORDER_PRODUCTS),\n    text: 'Your cart contains one or more items that are on pre-order. Items on pre-order will ship as soon as they become available. In-stock items will ship immediately. If your order contains more than one Spark LIVE, Spark CAB or a mix of both, please note that each unit will ship separately due to their size.',\n  },\n  */\n  {\n    name: `Cart containing Spark CAB and Custom grille`,\n    condition: () =\u003e\n      detectCartIncludesSkus(cartItems, [PRODUCT_SKU.SPARK_CAB]) \u0026\u0026 detectCartIncludesSkus(cartItems, CUSTOM_GRILLES),\n    text: 'Your cart contains one or more Spark CABs and a personalized amp grille. Please note that the personalized grilles will ship separately from all the items in your order and each Spark CAB unit will ship separately due to their size.',\n  },\n  {\n    name: 'Spark CAB + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: [PRODUCT_SKU.SPARK_CAB],\n        limitQuantity: 2,\n      }),\n    text: 'Your cart contains one or more Spark CABs. Please note that each Spark CAB unit will ship separately due to their size.',\n  },\n  {\n    name: 'Custom grille + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: CUSTOM_GRILLES,\n      }),\n    text: 'Customized grille will ship separately from the rest of the order.',\n  },\n  // 20241219 OSK-1460 hide pre-order popup\n  /*\n  {\n    // Spark2 pre-order\n    name: 'Spark2 + any other hardware',\n    condition: () =\u003e\n      cartHasOtherHardware({\n        skus: Spark2,\n      }),\n    text: 'Your cart contains one or more items that are on pre-order. Items on pre-order will ship as soon as they become available. In-stock items will ship immediately.  If your order contains more than one Spark LIVE, Spark CAB or a mix of both, please note that each unit will ship separately due to their size.',\n  },\n  */\n];\n\nPromise.resolve()\n  .then(detectPGModelReady)\n  .then(() =\u003e logger('detectPGModelReady'))\n  .then(() =\u003e promisifyfindFirstMatchedRule(CART_VALIDATION_RULES)) // Find the first matched rule\n  .then((rule) =\u003e {\n    logger(`detect:${rule.name}`);\n    return window.PGModel.alertPGSitePopup({\n      content: rule.text,\n      acceptCTAText: 'CONTINUE',\n    });\n  })\n  .catch((err) =\u003e {\n    console.log('[OSK-945, OSK-1140] not fitting rule');\n  });\n\nlogger('start');\n","trigger":{"include_pages":[{"url":"https://staging.positivegrid.com/cart","type":"exact"}],"exclude_pages":[{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"},{"url":"portal-staging.positivegrid.com","type":"contains"},{"url":"portal.positivegrid.com","type":"contains"}]},"_id":"65d6b868d031b614c00e97c9"},{"uses_overlay":false,"type":"js","parametrized_definition":"console.log('%cSpark Neo PDP CTA soldout action - staging, exponea-id:676a9686ab0c681899ee2e46', 'background:#ffd500;');\nconst pdpSoldOutCTA = document.getElementById('pg__pdp-sold-out');\n\nfunction createAmazonBtn() {\n  const btn = document.createElement('a');\n  btn.id = 'exponea-tag-manager-676a9686ab0c681899ee2e46';\n  // btn.style.display = 'flex';\n  btn.style.display = 'none';\n  btn.style.marginTop = '12px';\n  btn.setAttribute('href', 'https://www.google.com'); // TODO: need correct URL\n  btn.setAttribute('target', '_blank');\n  btn.setAttribute('data-exponea-tag-manager', '676a9686ab0c681899ee2e46');\n  btn.setAttribute('class', 'pg-btn pg-btn--xl pg-btn--outline');\n  btn.innerText = 'Amazon Store'; // TODO: need corrent Copy\n  return btn;\n}\nconst amazonBtn = createAmazonBtn();\nconst parentElement = pdpSoldOutCTA.parentNode;\nparentElement.insertBefore(amazonBtn, pdpSoldOutCTA.nextSibling);\n\nfunction checkIsSoldOut() {\n  if (pdpSoldOutCTA.style.display === '') {\n    // sold out\n    amazonBtn.style.display = 'flex';\n  } else {\n    amazonBtn.style.display = 'none';\n  }\n}\n\nconst mutation = new MutationObserver(checkIsSoldOut);\nmutation.observe(pdpSoldOutCTA, {\n  attributes: true,\n  childList: true,\n});\ncheckIsSoldOut();\n","trigger":{"include_pages":[{"url":"https://staging.positivegrid.com/products/spark-elephant","type":"contains"}],"exclude_pages":[{"url":"utm_source=e2e","type":"contains"},{"url":"localhost","type":"contains"},{"url":"myshopify.com","type":"contains"}]},"_id":"676a9686ab0c681899ee2e46"},{"uses_overlay":false,"type":"js","parametrized_definition":"(() =\u003e {\n  console.log('%c⚙️[OSK-1478,OSK-1769][staging] Spark NEO/Live PLP Redirect', 'background:#fed501');\n\n  const PRODUCTS = [\n    {\n      title: 'spark-neo',\n      redirect_url: '/pages/spark-neo',\n      exclude_hosts: [],\n    },\n    {\n      title: 'spark-live',\n      redirect_url: '/pages/spark-live',\n      exclude_hosts: [\n        // jp site don't have pages/spark-live\n        'jp.positivegrid.com',\n      ],\n    },\n  ];\n\n  /**\n   * Check if current host should be excluded from redirects\n   */\n  const shouldExcludeHost = (excludeHosts) =\u003e {\n    if (!excludeHosts || excludeHosts.length === 0) return false;\n    const currentHost = window.location.hostname;\n    return excludeHosts.some((host) =\u003e currentHost === host);\n  };\n\n  /**\n   * During the Spark NEO/Live launch period,\n   * we will need to redirect the image and CTA clicks on the Spark NEO/Live Product Cards to specific pages.\n   */\n\n  // Handle product card clicks\n  PRODUCTS.forEach((product) =\u003e {\n    const productATag = document.querySelector(`pg-product-card[data-product-title=\"${product.title}\"] a`);\n    if (productATag) {\n      productATag.setAttribute('data-redirect-url', product.redirect_url);\n      productATag.addEventListener('click', (e) =\u003e {\n        // Check if current host should be excluded\n        if (shouldExcludeHost(product.exclude_hosts)) {\n          return; // Don't redirect on excluded hosts\n        }\n\n        e.preventDefault();\n        window.location.href = product.redirect_url;\n      });\n    }\n  });\n\n  // Handle predictive search clicks\n  const predictiveSearch = document.querySelector('pg-predictive-search');\n\n  if (predictiveSearch) {\n    predictiveSearch.addEventListener('click', (e) =\u003e {\n      // 獲取事件的目標元素\n      const { target } = e;\n\n      // Check if any product matches the clicked link\n      const matchedProduct = PRODUCTS.find((product) =\u003e {\n        const closestLink = target.closest(`a[href*=\"${product.title}\"]`);\n        return closestLink;\n      });\n\n      // If a product matches, execute redirect\n      if (matchedProduct) {\n        // Check if current host should be excluded\n        if (shouldExcludeHost(matchedProduct.exclude_hosts)) {\n          return; // Don't redirect on excluded hosts\n        }\n\n        e.preventDefault();\n        window.location.href = matchedProduct.redirect_url;\n      }\n    });\n  }\n})();\n","trigger":{"include_pages":[{"url":"staging.positivegrid.com","type":"contains"}],"exclude_pages":null},"_id":"6785cc07d132224c56efbb62"},{"uses_overlay":false,"type":"js","parametrized_definition":"(() =\u003e {\n  console.log('%c⚙️[OSK-1478,OSK-1769] Spark NEO/Live PLP Redirect', 'background:#fed501');\n\n  const PRODUCTS = [\n    {\n      title: 'spark-neo',\n      redirect_url: '/pages/spark-neo',\n      exclude_hosts: [],\n    },\n    {\n      title: 'spark-live',\n      redirect_url: '/pages/spark-live',\n      exclude_hosts: [\n        // jp site don't have pages/spark-live\n        'jp.positivegrid.com', // https://positivegrid.atlassian.net/browse/OSK-1769\n      ],\n    },\n  ];\n\n  /**\n   * Check if current host should be excluded from redirects\n   */\n  const shouldExcludeHost = (excludeHosts) =\u003e {\n    if (!excludeHosts || excludeHosts.length === 0) return false;\n    const currentHost = window.location.hostname;\n    return excludeHosts.some((host) =\u003e currentHost === host);\n  };\n\n  /**\n   * During the Spark NEO/Live launch period,\n   * we will need to redirect the image and CTA clicks on the Spark NEO/Live Product Cards to specific pages.\n   */\n\n  // Handle product card clicks\n  PRODUCTS.forEach((product) =\u003e {\n    const productATag = document.querySelector(`pg-product-card[data-product-title=\"${product.title}\"] a`);\n    if (productATag) {\n      productATag.setAttribute('data-redirect-url', product.redirect_url);\n      productATag.addEventListener('click', (e) =\u003e {\n        // Check if current host should be excluded\n        if (shouldExcludeHost(product.exclude_hosts)) {\n          return; // Don't redirect on excluded hosts\n        }\n\n        e.preventDefault();\n        window.location.href = product.redirect_url;\n      });\n    }\n  });\n\n  // Handle predictive search clicks\n  const predictiveSearch = document.querySelector('pg-predictive-search');\n\n  if (predictiveSearch) {\n    predictiveSearch.addEventListener('click', (e) =\u003e {\n      // 獲取事件的目標元素\n      const { target } = e;\n\n      // Check if any product matches the clicked link\n      const matchedProduct = PRODUCTS.find((product) =\u003e {\n        const closestLink = target.closest(`a[href*=\"${product.title}\"]`);\n        return closestLink;\n      });\n\n      // If a product matches, execute redirect\n      if (matchedProduct) {\n        // Check if current host should be excluded\n        if (shouldExcludeHost(matchedProduct.exclude_hosts)) {\n          return; // Don't redirect on excluded hosts\n        }\n\n        e.preventDefault();\n        window.location.href = matchedProduct.redirect_url;\n      }\n    });\n  }\n})();\n","trigger":{"include_pages":[{"url":"www.positivegrid.com","type":"contains"},{"url":"ca.positivegrid.com","type":"contains"},{"url":"au.positivegrid.com","type":"contains"},{"url":"eu.positivegrid.com","type":"contains"},{"url":"uk.positivegrid.com","type":"contains"},{"url":"jp.positivegrid.com","type":"contains"}],"exclude_pages":null},"_id":"67a993b9ee0b370304c1a55a"},{"uses_overlay":true,"type":"js","parametrized_definition":"const utils = {\n  createLogger(moduleName, style = 'background:#fed501;') {\n    return (...args) =\u003e {\n      console.log.apply(console, [`%c ${moduleName} `, style, ...args]);\n    };\n  },\n  waitForCondition(fn, times = 30) {\n    return new Promise((resolve, reject) =\u003e {\n      let executeCount = 0;\n      const timeId = window.setInterval(() =\u003e {\n        if (executeCount \u003e= times) {\n          clearInterval(timeId);\n          reject(new Error('Not ready'));\n          return;\n        }\n        const result = fn();\n        if (result) {\n          clearInterval(timeId);\n          resolve(result);\n        }\n        executeCount += 1;\n      }, 200);\n    });\n  },\n  anyMatchInArray: (arrA, arrB) =\u003e arrA.some((item) =\u003e arrB.includes(item)),\n};\nconst BIAS_X = 'L2201';\nconst BIAS_X_UPGRADE = 'TL2201';\nconst BIAS_X_SET = [BIAS_X, BIAS_X_UPGRADE];\n\nconst logger = utils.createLogger('OSK-1814');\nlogger('script loaded');\n\nconst setContainerVisible = (isVisible) =\u003e {\n  const container = document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n  if (!container) {\n    return;\n  }\n  if (isVisible) {\n    container.classList.remove('hidden');\n  } else {\n    container.classList.add('hidden');\n  }\n};\n\nconst adjustAnnouncementContent = () =\u003e {\n  logger('adjustAnnouncementContent');\n  const container = document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n  if (!container) {\n    return;\n  }\n  container.innerHTML = ``;\n  container.setAttribute('data-exponea', 'OSK-1793');\n};\n\nconst isCustomerMetafieldReady = () =\u003e {\n  const ele = document.getElementById('customer-metafields-container');\n  if (!ele) {\n    return null;\n  }\n  return JSON.parse(ele.innerHTML);\n};\nconst isAnnouncementBarContainerReady = () =\u003e !!document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n\nPromise.resolve()\n  .then(() =\u003e utils.waitForCondition(isAnnouncementBarContainerReady))\n  .then(() =\u003e setContainerVisible(false))\n  .then(() =\u003e utils.waitForCondition(isCustomerMetafieldReady))\n  .then((customerData) =\u003e utils.anyMatchInArray(customerData.licenses, BIAS_X_SET))\n  .then((customerHasBiasX) =\u003e {\n    if (!customerHasBiasX) {\n      console.log('Customer does not have BIAS X or BIAS X Upgrade');\n      throw new Error('Customer does not have BIAS X or BIAS X Upgrade');\n    }\n  })\n  .then(() =\u003e {\n    adjustAnnouncementContent();\n  })\n  .catch((error) =\u003e {\n    // do nothing\n  })\n  .finally(() =\u003e {\n    setContainerVisible(true);\n  });\n","trigger":{"include_pages":[{"url":"https://member-staging.positivegrid.com","type":"contains"},{"url":"http://bcom-dev.positivegrid.com","type":"contains"}],"exclude_pages":null},"_id":"68c129cf661e7de9c7c9a127"},{"uses_overlay":false,"type":"js","parametrized_definition":"const utils = {\n  createLogger(moduleName, style = 'background:#fed501;') {\n    return (...args) =\u003e {\n      console.log.apply(console, [`%c ${moduleName} `, style, ...args]);\n    };\n  },\n  waitForCondition(fn, times = 30) {\n    return new Promise((resolve, reject) =\u003e {\n      let executeCount = 0;\n      const timeId = window.setInterval(() =\u003e {\n        if (executeCount \u003e= times) {\n          clearInterval(timeId);\n          reject(new Error('Not ready'));\n          return;\n        }\n        const result = fn();\n        if (result) {\n          clearInterval(timeId);\n          resolve(result);\n        }\n        executeCount += 1;\n      }, 200);\n    });\n  },\n  anyMatchInArray: (arrA, arrB) =\u003e arrA.some((item) =\u003e arrB.includes(item)),\n};\nconst BIAS_X = 'L2201';\nconst BIAS_X_UPGRADE = 'TL2201';\nconst BIAS_X_SET = [BIAS_X, BIAS_X_UPGRADE];\n\nconst logger = utils.createLogger('OSK-1814');\nlogger('script loaded');\n\nconst setContainerVisible = (isVisible) =\u003e {\n  const container = document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n  if (!container) {\n    return;\n  }\n  if (isVisible) {\n    container.classList.remove('hidden');\n  } else {\n    container.classList.add('hidden');\n  }\n};\n\nconst adjustAnnouncementContent = () =\u003e {\n  logger('adjustAnnouncementContent');\n  const container = document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n  if (!container) {\n    return;\n  }\n  container.innerHTML = ``;\n  container.setAttribute('data-exponea', 'OSK-1814');\n};\n\nconst isCustomerMetafieldReady = () =\u003e {\n  const ele = document.getElementById('customer-metafields-container');\n  if (!ele) {\n    return null;\n  }\n  return JSON.parse(ele.innerHTML);\n};\nconst isAnnouncementBarContainerReady = () =\u003e !!document.querySelector('[data-component=\"AnnouncementBarContainer\"]');\n\nPromise.resolve()\n  .then(() =\u003e utils.waitForCondition(isAnnouncementBarContainerReady))\n  .then(() =\u003e setContainerVisible(false))\n  .then(() =\u003e utils.waitForCondition(isCustomerMetafieldReady))\n  .then((customerData) =\u003e utils.anyMatchInArray(customerData.licenses, BIAS_X_SET))\n  .then((customerHasBiasX) =\u003e {\n    if (!customerHasBiasX) {\n      throw new Error('Customer does not have BIAS X or BIAS X Upgrade');\n    }\n  })\n  .then(() =\u003e {\n    adjustAnnouncementContent();\n  })\n  .catch((error) =\u003e {\n    // do nothing\n  })\n  .finally(() =\u003e {\n    setContainerVisible(true);\n  });\n","trigger":{"include_pages":[{"url":"https://member.positivegrid.com","type":"contains"}],"exclude_pages":null},"_id":"68ca27c3d49909bda46587d4"},{"uses_overlay":false,"type":"js","parametrized_definition":"document.documentElement.setAttribute('seg', 'spark-owners')","trigger":{"include_pages":[{"url":"?owners=spark","type":"contains"},{"url":"\u0026owners=spark","type":"contains"}],"exclude_pages":null},"_id":"691dae5f98dd01bf2684e537"},{"uses_overlay":false,"type":"js","parametrized_definition":"document.documentElement.setAttribute('seg', 'biasx-owners')","trigger":{"include_pages":[{"url":"?owners=biasx","type":"contains"},{"url":"\u0026owners=biasx","type":"contains"}],"exclude_pages":null},"_id":"691daee5a395d5bab0080fdf"},{"uses_overlay":false,"type":"js","parametrized_definition":"// https://positivegrid.atlassian.net/jira/software/projects/OSK/boards/3?selectedIssue=OSK-503\n// v2.1: also swaps .product-tabs-dropdown__cta; patch fixed 120px width so label fits on one line\n(function () {\n  const SEA_COUNTRYCODE_LIST = [\n    'VN', 'LA', 'KH', 'TH', 'MM', 'MY',\n    'SG', 'ID', 'BN', 'PH', 'TL', 'TW'\n  ];\n\n  const TARGET_PRODUCT_TYPE = ['Physical', 'Others'];\n  const DEALER_LABEL = 'Find a dealer';\n  const DEALER_URL = '/pages/online-retailers';\n  const DROPDOWN_CTA_CLASS = 'product-tabs-dropdown__cta';\n  const CTA_SELECTOR = '.pg-add-to-cart-CTA, .' + DROPDOWN_CTA_CLASS;\n\n  const detectCTA = () =\u003e !!document.querySelector(CTA_SELECTOR);\n  const detectPGModelReady = () =\u003e !!(window.PGModel \u0026\u0026 window.PGModel.getUserLocation);\n  const isPGModelAndCTAReady = () =\u003e detectPGModelReady() \u0026\u0026 detectCTA();\n\n  // dropdown CTA has no data-type attr — fall back to the main CTA's data-type on the same page\n  const resolveDataType = (element) =\u003e {\n    if (element.dataset.type) return element.dataset.type;\n    const typedCTA = document.querySelector('.pg-add-to-cart-CTA[data-type]');\n    return typedCTA ? typedCTA.dataset.type : null;\n  };\n\n  // theme CSS locks the dropdown CTA at width:120px — \"Find a dealer\" wraps and overflows it\n  const patchDropdownCtaStyle = (element) =\u003e {\n    element.style.width = 'auto';\n    element.style.whiteSpace = 'nowrap';\n  };\n\n  const modifyCTA = (element) =\u003e {\n    const dataType = resolveDataType(element);\n    if (!TARGET_PRODUCT_TYPE.includes(dataType)) return;\n    element.setAttribute('data-changed', '');\n    element.innerHTML = DEALER_LABEL;\n    if (element.classList.contains(DROPDOWN_CTA_CLASS)) {\n      patchDropdownCtaStyle(element);\n    }\n    element.addEventListener('click', (e) =\u003e {\n      e.stopPropagation();\n      e.preventDefault();\n      window.location.href = DEALER_URL;\n    }, true);\n  };\n\n  // Vue re-render / pg-dynamic-translate may overwrite the label — re-assert every tick\n  const reassertLabels = () =\u003e {\n    document\n      .querySelectorAll('.pg-add-to-cart-CTA[data-changed], .' + DROPDOWN_CTA_CLASS + '[data-changed]')\n      .forEach((element) =\u003e {\n        if (element.textContent.trim() !== DEALER_LABEL) {\n          element.innerHTML = DEALER_LABEL;\n        }\n      });\n  };\n\n  const triggerCTAModification = (countryCode) =\u003e {\n    if (!SEA_COUNTRYCODE_LIST.includes(countryCode)) return;\n    document.querySelectorAll(CTA_SELECTOR).forEach((element) =\u003e {\n      if (!element.hasAttribute('data-changed')) {\n        modifyCTA(element);\n      }\n    });\n    reassertLabels();\n  };\n\n  const checkPGModelAndModifyCTA = () =\u003e {\n    window.PGModel.getUserLocation().then(({ country_code2 }) =\u003e {\n      setInterval(() =\u003e {\n        triggerCTAModification(country_code2);\n      }, 500);\n    });\n  };\n\n  const callResolve = (func) =\u003e\n    new Promise((resolve, reject) =\u003e (func() ? resolve('') : reject('')));\n\n  const retry = (func, retryTimes) =\u003e\n    new Promise((resolve, reject) =\u003e {\n      const retryAttempt = () =\u003e {\n        func()\n          .then(resolve)\n          .catch(() =\u003e {\n            if (retryTimes \u003e 1) {\n              setTimeout(retryAttempt, 500);\n              retryTimes--;\n            } else {\n              reject('');\n            }\n          });\n      };\n      retryAttempt();\n    });\n\n  console.log('SEA Find-a-dealer CTA swap v2.1 (incl. product-tabs dropdown)');\n\n  retry(() =\u003e callResolve(isPGModelAndCTAReady), 30)\n    .then(checkPGModelAndModifyCTA)\n    .catch((err) =\u003e console.log(err));\n})();","trigger":{"include_pages":[{"url":"https://au.positivegrid.com/","type":"contains"}],"exclude_pages":null},"_id":"6a4719f47e81e1979ce2964e"},{"uses_overlay":false,"type":"js","parametrized_definition":"// https://positivegrid.atlassian.net/jira/software/projects/OSK/boards/3?selectedIssue=OSK-503\n// v4.1 (Alto): fix collection-card layout shift + a11y name\n//   - v4.0 bug: .pg-btn has letter-spacing:1px (absolute px) — with font-size:0\n//     the hidden \"ADD TO CART\" still contributed 11px phantom width (1px/char),\n//     shifting the ::after label. Base rule now zeroes letter-spacing too;\n//     each ::after re-declares its own spacing.\n//   - Marked buttons get aria-label so screen readers hear only \"Find a dealer\".\n(function () {\n  const SEA_COUNTRYCODE_LIST = [\n    'VN', 'LA', 'KH', 'TH', 'MM', 'MY',\n    'SG', 'ID', 'BN', 'PH', 'TL', 'TW'\n  ];\n  const PAGE_MARKET_TOKENS = ['au'];\n  const TARGET_PRODUCT_TYPE = ['Physical', 'Others'];\n  const DEALER_LABEL = 'Find a dealer';\n  const GEO_ENDPOINT = '/api/pg/geo';\n  const SAFETY_TICK_MS = 1000;\n  const ATTR = 'data-dealer-cta';\n\n  const DROPDOWN_CTA_CLASS = 'product-tabs-dropdown__cta';\n  const CARD_CTA_SELECTOR = '[data-dl-product] button.pg-btn--outline';\n  const CTA_SELECTOR =\n    '#pg__add-to-cart, #products-tabs__buy-btn, .' + DROPDOWN_CTA_CLASS + ', ' +\n    CARD_CTA_SELECTOR;\n\n  // Font sizes mirror each surface's own CSS (globals.css):\n  //   pg-btn--xl 18px / pg-btn--sm 12px / belt CTAs .75rem → 1rem @lg\n  const CSS = `\n    [${ATTR}] { font-size: 0 !important; letter-spacing: 0 !important; }\n    [${ATTR}] .pg-spinner-border { display: none !important; }\n    #pg__add-to-cart[${ATTR}]::after {\n      content: '${DEALER_LABEL}'; font-size: 18px; letter-spacing: 1px;\n    }\n    [data-dl-product] button.pg-btn--outline[${ATTR}]::after {\n      content: '${DEALER_LABEL}'; font-size: 12px; letter-spacing: 1px;\n    }\n    #products-tabs__buy-btn[${ATTR}]::after,\n    .${DROPDOWN_CTA_CLASS}[${ATTR}]::after {\n      content: '${DEALER_LABEL}'; font-size: .75rem; letter-spacing: .04em;\n    }\n    @media (min-width: 1024px) {\n      #products-tabs__buy-btn[${ATTR}]::after,\n      .${DROPDOWN_CTA_CLASS}[${ATTR}]::after { font-size: 1rem; }\n      .${DROPDOWN_CTA_CLASS}[${ATTR}] { width: auto !important; white-space: nowrap; }\n    }\n  `;\n\n  const pageMarket = () =\u003e {\n    const seg = (location.pathname.split('/')[1] || '').toLowerCase();\n    return /^[a-z]{2}(-[a-z]{2})?$/.test(seg) ? seg : 'us';\n  };\n  const isTargetPage = () =\u003e PAGE_MARKET_TOKENS.includes(pageMarket());\n  const dealerUrl = () =\u003e {\n    const token = pageMarket();\n    return (token === 'us' ? '' : '/' + token) + '/pages/online-retailers';\n  };\n\n  let lastPathname = location.pathname;\n  let dlWatermark = 0; // ignore dl_view_item pushed before the last SPA route change\n\n  const currentPdpType = () =\u003e {\n    if (!location.pathname.includes('/products/')) return null;\n    const dl = window.dataLayer || [];\n    for (let i = dl.length - 1; i \u003e= dlWatermark; i--) {\n      if (dl[i] \u0026\u0026 dl[i].event === 'dl_view_item') {\n        try { return dl[i].ecommerce.detail.products[0].category || null; }\n        catch (e) { return null; }\n      }\n    }\n    return null;\n  };\n\n  const cardType = (element) =\u003e {\n    const wrapper = element.closest('[data-dl-product]');\n    if (!wrapper) return null;\n    try { return JSON.parse(wrapper.getAttribute('data-dl-product')).category || null; }\n    catch (e) { return null; }\n  };\n\n  const scan = () =\u003e {\n    if (location.pathname !== lastPathname) {\n      lastPathname = location.pathname;\n      dlWatermark = (window.dataLayer || []).length;\n    }\n    if (!isTargetPage()) return;\n    const pdpType = currentPdpType();\n    document.querySelectorAll(CTA_SELECTOR).forEach((element) =\u003e {\n      const type = element.matches(CARD_CTA_SELECTOR) ? cardType(element) : pdpType;\n      if (TARGET_PRODUCT_TYPE.includes(type)) {\n        if (!element.hasAttribute(ATTR)) {\n          element.setAttribute(ATTR, '');\n          element.setAttribute('aria-label', DEALER_LABEL); // a11y name = label only\n        }\n        if (element.disabled) element.disabled = false; // dealer link stays clickable at sold-out\n      } else if (element.hasAttribute(ATTR)) {\n        element.removeAttribute(ATTR);\n        element.removeAttribute('aria-label');\n      }\n    });\n  };\n\n  // One delegated capture-phase listener: runs before React's bubble-phase\n  // onClick, survives unmount/remount, nothing to clean up per element.\n  document.addEventListener('click', (e) =\u003e {\n    const hit = e.target \u0026\u0026 e.target.closest \u0026\u0026 e.target.closest(CTA_SELECTOR);\n    if (!hit || !hit.hasAttribute(ATTR)) return;\n    e.stopPropagation();\n    e.preventDefault();\n    window.location.href = dealerUrl();\n  }, true);\n\n  const start = () =\u003e {\n    if (!document.getElementById('pg-dealer-cta-style')) {\n      const style = document.createElement('style');\n      style.id = 'pg-dealer-cta-style';\n      style.textContent = CSS;\n      document.head.appendChild(style);\n    }\n    scan();\n    // Pre-paint re-mark: mutation callbacks run as microtasks before the frame\n    // paints, so a remounted button gets marked before it's ever visible.\n    let queued = false;\n    const observer = new MutationObserver(() =\u003e {\n      if (queued) return;\n      queued = true;\n      queueMicrotask(() =\u003e { queued = false; scan(); });\n    });\n    observer.observe(document.body, {\n      subtree: true,\n      childList: true,\n      attributes: true,\n      attributeFilter: ['disabled'],\n    });\n    setInterval(scan, SAFETY_TICK_MS);\n  };\n\n  // Geo gate — fail-safe: any error / null country → do nothing.\n  const fetchCountry = (attemptsLeft) =\u003e\n    fetch(GEO_ENDPOINT)\n      .then((res) =\u003e res.json())\n      .then((data) =\u003e data.country_code || null)\n      .catch(() =\u003e attemptsLeft \u003e 1\n        ? new Promise((resolve) =\u003e setTimeout(() =\u003e resolve(fetchCountry(attemptsLeft - 1)), 2000))\n        : null);\n\n  console.log('SEA Find-a-dealer CTA swap v4.1 (Alto)');\n\n  fetchCountry(3).then((countryCode) =\u003e {\n    if (!countryCode || !SEA_COUNTRYCODE_LIST.includes(countryCode)) return;\n    start();\n  });\n})();","trigger":{"include_pages":[{"url":"https://alto.positivegrid.com/au/","type":"contains"},{"url":"https://www.positivegrid.com/au","type":"contains"}],"exclude_pages":null},"_id":"6a55dd1f5ce9dfdb3ca53273"}],"vars":{"data":[{"id":"65828710c4e21205866ce442","name":"Language test","variable":{"type":"data_layer","data_layer":{"name":"lang"}}},{"id":"6584fe69845bc306b10ea97d","name":"Weglot Variable Test","variable":{"type":"global_variable","global_variable":{"name":"Weglot.getCurrentLang()"}}},{"id":"65852b63c468355a6c7c3d34","name":"Weglot Fn Test","variable":{"type":"custom_function","custom_function":{"body":"return window.localStorage.wglang || 'en';"}}}]}}