PageSourceSearch

https://balkonkraftwerk-express.de/password

html balkonkraftwerk-express.de collected 2026-10-09 22:50:17 UTC 136,513 bytes, 2,595 lines download raw bytes

1<!doctype html>
2<html class="js full-height" lang="de">
3  <head>
4    <meta charset="utf-8">
5    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6    <meta name="viewport" content="width=device-width,initial-scale=1">
7    <meta name="theme-color" content="">
8    <link rel="canonical" href="https://balkonkraftwerk-express.de/password"><link rel="icon" type="image/png" href="//balkonkraftwerk-express.de/cdn/shop/files/bkw_favicon.png?crop=center&height=32&v=1727098671&width=32"><link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin><title>Balkonkraftwerk-Express</title>
9
10    <meta name="description" content="">
11
12    
13
14<meta property="og:site_name" content="Balkonkraftwerk-Express">
15<meta property="og:url" content="https://balkonkraftwerk-express.de">
16<meta property="og:title" content="Balkonkraftwerk-Express">
17<meta property="og:type" content="website">
18<meta property="og:description" content="Hochwertige Balkonkraftwerke für zuhause!: Plug-&amp;-Play-Systeme! ✔ Einfach! ✔ Nachhaltige Stromerzeugung ➜ Jetzt kaufen!"><meta property="og:image" content="http://balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?height=628&pad_color=ffffff&v=1691081304&width=1200">
19  <meta property="og:image:secure_url" content="https://balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?height=628&pad_color=ffffff&v=1691081304&width=1200">
20  <meta property="og:image:width" content="1200">
21  <meta property="og:image:height" content="628"><meta name="twitter:card" content="summary_large_image">
22<meta name="twitter:title" content="Balkonkraftwerk-Express">
23<meta name="twitter:description" content="Hochwertige Balkonkraftwerke für zuhause!: Plug-&amp;-Play-Systeme! ✔ Einfach! ✔ Nachhaltige Stromerzeugung ➜ Jetzt kaufen!">
24
25
26    
26<script>window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.start');</script>
26<meta name="google-site-verification" content="Y2kziul2JQywvNKrw2cdP6JXST2V-5oI_Ot_4d0kW5c">
27<meta id="shopify-digital-wallet" name="shopify-digital-wallet" content="/55579017562/digital_wallets/dialog">
28<meta id="in-context-paypal-metadata" data-shop-id="55579017562" data-venmo-supported="false" data-environment="production" data-locale="de_DE" data-paypal-v4="true" data-currency="EUR">
29<link rel="ucp" href="/.well-known/ucp" version="2026-08-25">
29<script async="async" src="/checkouts/internal/preloads.js?locale=de-DE"></script>
29
30<link rel="preconnect" href="https://shop.app" crossorigin="anonymous">
31<script async="async" src="https://shop.app/checkouts/internal/preloads.js?locale=de-DE&shop_id=55579017562" crossorigin="anonymous"></script>
vendor: 1 bytes, line 31
31
32<script id="apple-pay-shop-capabilities" type="application/json">{"shopId":55579017562,"countryCode":"DE","currencyCode":"EUR","merchantCapabilities":["supports3DS"],"merchantId":"gid:\/\/shopify\/Shop\/55579017562","merchantName":"Balkonkraftwerk-Express","requiredBillingContactFields":["postalAddress","email"],"requiredShippingContactFields":["postalAddress","email"],"shippingType":"shipping","supportedNetworks":["visa","masterCard","maestro"],"total":{"type":"pending","label":"Balkonkraftwerk-Express","amount":"1.00"},"shopifyPaymentsEnabled":true,"supportsSubscriptions":true}</script>
vendor: 1 bytes, line 32
32
33<script>var Shopify = Shopify || {};
34Shopify.shop = "e94e42.myshopify.com";
35Shopify.locale = "de";
36Shopify.currency = {"active":"EUR","rate":"1.0"};
37Shopify.country = "DE";
38Shopify.theme = {"name":"Theme 10.May 2026","id":193346863450,"schema_name":"Dawn","schema_version":"14.0.0","theme_store_id":887,"role":"main"};
39Shopify.theme.handle = "null";
40Shopify.theme.style = {"id":null,"handle":null};
41Shopify.cdnHost = "balkonkraftwerk-express.de/cdn";
42Shopify.routes = Shopify.routes || {};
43Shopify.routes.root = "/";
44Shopify.shopJsCdnBaseUrl = "https://cdn.shopify.com/shopifycloud/shop-js";
45Shopify.SignInWithShop = Shopify.SignInWithShop || {};
46Shopify.SignInWithShop.User = Shopify.SignInWithShop.User || {};
47Shopify.SignInWithShop.User.recognized = false;</script>
vendor: 1 bytes, line 47
47
48<script type="module">!function(o){(o.Shopify=o.Shopify||{}).modules=!0}(window);</script>
vendor: 1 bytes, line 48
48
49<script>!function(o){function n(){var o=[];function n(){o.push(Array.prototype.slice.apply(arguments))}return n.q=o,n}var t=o.Shopify=o.Shopify||{};t.loadFeatures=n(),t.autoloadFeatures=n()}(window);</script>
vendor: 1 bytes, line 49
49
50<script>
51  window.ShopifyPay = window.ShopifyPay || {};
52  window.ShopifyPay.apiHost = "shop.app\/pay";
53  window.ShopifyPay.redirectState = null;
54</script>
vendor: 1 bytes, line 54
54
55<script>
56  window.Shopify = window.Shopify || {};
57  window.Shopify.SignInWithShop = window.Shopify.SignInWithShop || {};
58  window.Shopify.SignInWithShop.assetMetrics = { sampleRate: 0.25 };
59  window.Shopify.SignInWithShop.eligible = true;
60</script>
vendor: 1 bytes, line 60
60
61<script id="shop-js-analytics" type="application/json">{"pageType":"password"}</script>
vendor: 1 bytes, line 61
61
62<script defer="defer" async type="module" src="https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.de.esm.js"></script>
vendor: 1 bytes, line 62
62
63<script type="module">
64  await import("https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.de.esm.js");
65
66  window.Shopify.SignInWithShop?.initShopCartSync?.({"fedCMEnabled":true,"windoidEnabled":true});
67
68</script>
vendor: 1 bytes, line 68
68
69<script>
70  window.Shopify = window.Shopify || {};
71  if (!window.Shopify.featureAssets) window.Shopify.featureAssets = {};
72  window.Shopify.featureAssets['shop-js'] = {"avatar":["modules/v2/loader.avatar.de.esm.js"],"checkout-modal":["modules/v2/loader.checkout-modal.de.esm.js"],"init-customer-accounts-sign-up":["modules/v2/loader.init-customer-accounts-sign-up.de.esm.js"],"init-customer-accounts":["modules/v2/loader.init-customer-accounts.de.esm.js"],"init-fed-cm":["modules/v2/loader.init-fed-cm.de.esm.js"],"init-shop-cart-sync":["modules/v2/loader.init-shop-cart-sync.de.esm.js"],"init-shop-email-lookup-coordinator":["modules/v2/loader.init-shop-email-lookup-coordinator.de.esm.js"],"init-shop-for-new-customer-accounts":["modules/v2/loader.init-shop-for-new-customer-accounts.de.esm.js"],"init-shop-user-recognition":["modules/v2/loader.init-shop-user-recognition.de.esm.js"],"init-windoid":["modules/v2/loader.init-windoid.de.esm.js"],"lead-capture":["modules/v2/loader.lead-capture.de.esm.js"],"listener":["modules/v2/loader.listener.de.esm.js"],"pay-button":["modules/v2/loader.pay-button.de.esm.js"],"payment-terms":["modules/v2/loader.payment-terms.de.esm.js"],"shop-button":["modules/v2/loader.shop-button.de.esm.js"],"shop-cart-sync":["modules/v2/loader.shop-cart-sync.de.esm.js"],"shop-cash-offers":["modules/v2/loader.shop-cash-offers.de.esm.js"],"shop-follow-button":["modules/v2/loader.shop-follow-button.de.esm.js"],"shop-login-button":["modules/v2/loader.shop-login-button.de.esm.js"],"shop-login":["modules/v2/loader.shop-login.de.esm.js"],"shop-toast-manager":["modules/v2/loader.shop-toast-manager.de.esm.js"],"shop-user-recognition":["modules/v2/loader.shop-user-recognition.de.esm.js"]};
73</script>
vendor: 1 bytes, line 73
73
74<script id="__st">var __st={"a":55579017562,"offset":7200,"reqid":"5823bc87-814a-4b96-beff-79d5c90e35af-1791586216","pageurl":"balkonkraftwerk-express.de\/password","u":"9885d72964f7","p":"password"};</script>
vendor: 1 bytes, line 74
74
75<script>window.ShopifyPaypalV4VisibilityTracking = true;</script>
vendor: 1 bytes, line 75
75
76<script id="captcha-bootstrap">!function(){'use strict';const t='contact',e='account',n='new_comment',o=[[t,t],['blogs',n],['comments',n],[t,'customer']],c=[[e,'customer_login'],[e,'guest_login'],[e,'recover_customer_password'],[e,'create_customer']],r=t=>t.map((([t,e])=>`form[action*='/${t}']:not([data-nocaptcha='true']) input[name='form_type'][value='${e}']`)).join(','),a=t=>()=>t?[...document.querySelectorAll(t)].map((t=>t.form)):[];function s(){const t=[...o],e=r(t);return a(e)}const i='password',u='form_key',d=['recaptcha-v3-token','g-recaptcha-response','h-captcha-response',i],f=()=>{try{return window.sessionStorage}catch{return}},m='__shopify_v',_=t=>t.elements[u];function p(t,e,n=!1){try{const o=window.sessionStorage,c=JSON.parse(o.getItem(e)),{data:r}=function(t){const{data:e,action:n}=t;return t[m]||n?{data:e,action:n}:{data:t,action:n}}(c);for(const[e,n]of Object.entries(r))t.elements[e]&&(t.elements[e].value=n);n&&o.removeItem(e)}catch(o){console.error('form repopulation failed',{error:o})}}const l='form_type',E='cptcha';function T(t){t.dataset[E]=!0}const w=window,h=w.document,L='Shopify',v='ce_forms',y='captcha';let A=!1;((t,e)=>{const n=(g='f06e6c50-85a8-45c8-87d0-21a2b65856fe',I='https://cdn.shopify.com/shopifycloud/storefront-forms-hcaptcha/ce_storefront_forms_captcha_hcaptcha.v1.5.3.iife.js',D={infoText:'Durch hCaptcha geschützt',privacyText:'Datenschutz',termsText:'Allgemeine Geschäftsbedingungen'},(t,e,n)=>{const o=w[L][v],c=o.bindForm;if(c)return c(t,g,e,D).then(n);var r;o.q.push([[t,g,e,D],n]),r=I,A||(h.body.append(Object.assign(h.createElement('script'),{id:'captcha-provider',async:!0,src:r})),A=!0)});var g,I,D;w[L]=w[L]||{},w[L][v]=w[L][v]||{},w[L][v].q=[],w[L][y]=w[L][y]||{},w[L][y].protect=function(t,e){n(t,void 0,e),T(t)},Object.freeze(w[L][y]),function(t,e,n,w,h,L){const[v,y,A,g]=function(t,e,n){const i=e?o:[],u=t?c:[],d=[...i,...u],f=r(d),m=r(i),_=r(d.filter((([t,e])=>n.includes(e))));return[a(f),a(m),a(_),s()]}(w,h,L),I=t=>{const e=t.target;return e instanceof HTMLFormElement?e:e&&e.form},D=t=>v().includes(t);t.addEventListener('submit',(t=>{const e=I(t);if(!e)return;const n=D(e)&&!e.dataset.hcaptchaBound&&!e.dataset.recaptchaBound,o=_(e),c=g().includes(e)&&(!o||!o.value);(n||c)&&t.preventDefault(),c&&!n&&(function(t){try{if(!f())return;!function(t){const e=f();if(!e)return;const n=_(t);if(!n)return;const o=n.value;o&&e.removeItem(o)}(t);const e=Array.from(Array(32),(()=>Math.random().toString(36)[2])).join('');!function(t,e){_(t)||t.append(Object.assign(document.createElement('input'),{type:'hidden',name:u})),t.elements[u].value=e}(t,e),function(t,e){const n=f();if(!n)return;const o=[...t.querySelectorAll(`input[type='${i}']`)].map((({name:t})=>t)),c=[...d,...o],r={};for(const[a,s]of new FormData(t).entries())c.includes(a)||(r[a]=s);n.setItem(e,JSON.stringify({[m]:1,action:t.action,data:r}))}(t,e)}catch(e){console.error('failed to persist form',e)}}(e),e.submit())}));const S=(t,e)=>{t&&!t.dataset[E]&&(n(t,e.some((e=>e===t))),T(t))};for(const o of['focusin','change'])t.addEventListener(o,(t=>{const e=I(t);D(e)&&S(e,y())}));const B=e.get('form_key'),M=e.get(l),P=B&&M;t.addEventListener('DOMContentLoaded',(()=>{const t=y();if(P)for(const e of t)e.elements[l].value===M&&p(e,B);[...new Set([...A(),...v().filter((t=>'true'===t.dataset.shopifyCaptcha))])].forEach((e=>S(e,t)))}))}(h,new URLSearchParams(w.location.search),n,t,e,['guest_login'])})(!0,!0)}();</script>
vendor: 1 bytes, line 76
76
77<script integrity="sha256-JjoPp5ZfB1sSAs5SQaol1x1GgvveM+BgmRzyDexInEQ=" data-source-attribution="shopify.loadfeatures" defer="defer" src="//balkonkraftwerk-express.de/cdn/shopifycloud/storefront/assets/storefront/load_feature-1bd60354.js" crossorigin="anonymous"></script>
vendor: 1 bytes, line 77
77
78<script>(function () {var userAgent = navigator.userAgent;var platform = navigator.platform;var maxTouchPoints = navigator.maxTouchPoints || 0;var isIOS = /iPad|iPhone|iPod/.test(platform) || (platform === 'MacIntel' && maxTouchPoints > 1);var isMacSafari = platform.indexOf('Mac') === 0 && /Safari/.test(userAgent) && !/Chrome|Chromium|CriOS|FxiOS|Edg|OPR|Android/.test(userAgent);var isAppleSafari = isIOS || isMacSafari;if (isAppleSafari) {fetch('/sf_private_access_tokens' + location.search).catch(function () {});}function browserMajorVersion(pattern) {var match = userAgent.match(pattern);return match ? parseInt(match[1], 10) : null;}function shouldLoadAutosizesPolyfill() {if (!window.PerformanceObserver?.supportedEntryTypes?.includes('paint')) {return false;}var chromeVersion = browserMajorVersion(/Chrome\/(\d+)/);if (chromeVersion !== null) {return chromeVersion < 126;}var firefoxVersion = browserMajorVersion(/Firefox\/(\d+)/);if (firefoxVersion !== null) {return firefoxVersion < 150;}var safariVersion = isAppleSafari ? browserMajorVersion(/Version\/(\d+).*Safari\//) : null;if (safariVersion !== null) {return safariVersion < 27;}return true;}if (shouldLoadAutosizesPolyfill()) {var autosizesScript = document.createElement('script');autosizesScript.async = true;autosizesScript.crossOrigin = 'anonymous';autosizesScript.src = "//balkonkraftwerk-express.de/cdn/shopifycloud/storefront/assets/storefront/autosizes-84416378.js";(document.head || document.documentElement).appendChild(autosizesScript);}window.ShopifyAnalytics = window.ShopifyAnalytics || {};window.ShopifyAnalytics.performance = window.ShopifyAnalytics.performance || {};(function () {var LONG_FRAME_THRESHOLD = 50;var longAnimationFrames = [];var activeRafId = null;function collectLongFrames() {var previousTime = null;function rafMonitor(now) {if (activeRafId === null) {return;}var delta = now - previousTime;if (delta > LONG_FRAME_THRESHOLD) {longAnimationFrames.push({startTime: previousTime,endTime: now,});}previousTime = now;activeRafId = requestAnimationFrame(rafMonitor);}previousTime = performance.now();activeRafId = requestAnimationFrame(rafMonitor);}if (!window.PerformanceObserver?.supportedEntryTypes?.includes('long-animation-frame')) {collectLongFrames();var timeoutId = setTimeout(function () {cancelAnimationFrame(activeRafId);}, 10000);window.ShopifyAnalytics.performance.getLongAnimationFrames = function (stopCollection) {if (stopCollection === undefined) {stopCollection = false;}if (stopCollection) {clearTimeout(timeoutId);cancelAnimationFrame(activeRafId);}return longAnimationFrames;};}})();})();</script>
78<script crossorigin="anonymous" defer="defer" src="//balkonkraftwerk-express.de/cdn/shopifycloud/storefront/assets/shopify_pay/storefront-f0e26bdf.js?v=20250812"></script>
vendor: 1 bytes, line 78
78
79<script id="shopify-origin-trials" async="async" integrity="sha256-qJbe/jEZBHtr5W/BlA2cKAz3vkXu6vJQyLjgvgCC86g=" src="//cdn.shopify.com/shopifycloud/storefront/assets/storefront/origin_trials-318ab40a.js" crossorigin="anonymous" onload="window.__shopifyOriginTrialsDone = true" onerror="window.__shopifyOriginTrialsDone = true"></script>
vendor: 1 bytes, line 79
79
80<script data-source-attribution="shopify.dynamic_checkout.buyer_consent">
81  function portableWalletsHideBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.add("hidden"),t.setAttribute("aria-hidden","true"),n.removeEventListener("click",e))}function portableWalletsShowBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.remove("hidden"),t.removeAttribute("aria-hidden"),n.addEventListener("click",e))}window.Shopify?.PaymentButton&&(window.Shopify.PaymentButton.hideBuyerConsent=portableWalletsHideBuyerConsent,window.Shopify.PaymentButton.showBuyerConsent=portableWalletsShowBuyerConsent);
82</script>
vendor: 1 bytes, line 82
82
83<script data-source-attribution="shopify.dynamic_checkout.cart.bootstrap">document.addEventListener("DOMContentLoaded",(function(){function t(){return document.querySelector("shopify-accelerated-checkout-cart, shopify-accelerated-checkout")}if(t())Shopify.PaymentButton.init();else{new MutationObserver((function(e,n){t()&&(Shopify.PaymentButton.init(),n.disconnect())})).observe(document.body,{childList:!0,subtree:!0})}}));
84</script>
84
85<link id="shopify-accelerated-checkout-styles" rel="stylesheet" media="screen" href="https://balkonkraftwerk-express.de/cdn/shopifycloud/portable-wallets/latest/accelerated-checkout-backwards-compat.css" crossorigin="anonymous">
86<style id="shopify-accelerated-checkout-cart">
87        #shopify-buyer-consent {
88  margin-top: 1em;
89  display: inline-block;
90  width: 100%;
91}
92
93#shopify-buyer-consent.hidden {
94  display: none;
95}
96
97#shopify-subscription-policy-button {
98  background: none;
99  border: none;
100  padding: 0;
101  text-decoration: underline;
102  font-size: inherit;
103  cursor: pointer;
104}
105
106#shopify-subscription-policy-button::before {
107  box-shadow: none;
108}
109
110      </style>
111
112<script id="shopify-cfh-end">window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.end');</script>
112
113
114
115    <style data-shopify>
116      @font-face {
117  font-family: Assistant;
118  font-weight: 400;
119  font-style: normal;
120  font-display: swap;
121  src: url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.9120912a469cad1cc292572851508ca49d12e768.woff2") format("woff2"),
122       url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.6e9875ce64e0fefcd3f4446b7ec9036b3ddd2985.woff") format("woff");
123}
124
125      @font-face {
126  font-family: Assistant;
127  font-weight: 700;
128  font-style: normal;
129  font-display: swap;
130  src: url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n7.bf44452348ec8b8efa3aa3068825305886b1c83c.woff2") format("woff2"),
131       url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n7.0c887fee83f6b3bda822f1150b912c72da0f7b64.woff") format("woff");
132}
133
134      
135      
136      @font-face {
137  font-family: Assistant;
138  font-weight: 400;
139  font-style: normal;
140  font-display: swap;
141  src: url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.9120912a469cad1cc292572851508ca49d12e768.woff2") format("woff2"),
142       url("//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.6e9875ce64e0fefcd3f4446b7ec9036b3ddd2985.woff") format("woff");
143}
144
145
146      
147        :root,
148        .color-background-1 {
149          --color-background: 255,255,255;
150          
151            --gradient-background: #ffffff;
152          
153          --color-foreground: 18,18,18;
154          --color-shadow: 18,18,18;
155          --color-button: 94,193,31;
156          --color-button-text: 255,255,255;
157          --color-secondary-button: 255,255,255;
158          --color-secondary-button-text: 18,18,18;
159          --color-link: 18,18,18;
160          --color-badge-foreground: 18,18,18;
161          --color-badge-background: 255,255,255;
162          --color-badge-border: 18,18,18;
163          --payment-terms-background-color: rgb(255 255 255);
164        }
165      
166        
167        .color-background-2 {
168          --color-background: 217,217,217;
169          
170            --gradient-background: #d9d9d9;
171          
172          --color-foreground: 18,18,18;
173          --color-shadow: 18,18,18;
174          --color-button: 18,18,18;
175          --color-button-text: 243,243,243;
176          --color-secondary-button: 217,217,217;
177          --color-secondary-button-text: 18,18,18;
178          --color-link: 18,18,18;
179          --color-badge-foreground: 18,18,18;
180          --color-badge-background: 217,217,217;
181          --color-badge-border: 18,18,18;
182          --payment-terms-background-color: rgb(217 217 217);
183        }
184      
185        
186        .color-inverse {
187          --color-background: 0,0,0;
188          
189            --gradient-background: #000000;
190          
191          --color-foreground: 255,255,255;
192          --color-shadow: 18,18,18;
193          --color-button: 255,255,255;
194          --color-button-text: 18,18,18;
195          --color-secondary-button: 0,0,0;
196          --color-secondary-button-text: 255,255,255;
197          --color-link: 255,255,255;
198          --color-badge-foreground: 255,255,255;
199          --color-badge-background: 0,0,0;
200          --color-badge-border: 255,255,255;
201          --payment-terms-background-color: rgb(0 0 0);
202        }
203      
204        
205        .color-accent-1 {
206          --color-background: 94,193,31;
207          
208            --gradient-background: #5ec11f;
209          
210          --color-foreground: 255,255,255;
211          --color-shadow: 18,18,18;
212          --color-button: 255,255,255;
213          --color-button-text: 94,193,31;
214          --color-secondary-button: 94,193,31;
215          --color-secondary-button-text: 255,255,255;
216          --color-link: 255,255,255;
217          --color-badge-foreground: 255,255,255;
218          --color-badge-background: 94,193,31;
219          --color-badge-border: 255,255,255;
220          --payment-terms-background-color: rgb(94 193 31);
221        }
222      
223        
224        .color-accent-2 {
225          --color-background: 94,193,31;
226          
227            --gradient-background: #5ec11f;
228          
229          --color-foreground: 255,255,255;
230          --color-shadow: 18,18,18;
231          --color-button: 255,255,255;
232          --color-button-text: 18,18,18;
233          --color-secondary-button: 94,193,31;
234          --color-secondary-button-text: 255,255,255;
235          --color-link: 255,255,255;
236          --color-badge-foreground: 255,255,255;
237          --color-badge-background: 94,193,31;
238          --color-badge-border: 255,255,255;
239          --payment-terms-background-color: rgb(94 193 31);
240        }
241      
242        
243        .color-scheme-2bbee085-e3ce-49f4-8eba-bd31d571ab49 {
244          --color-background: 18,18,18;
245          
246            --gradient-background: #121212;
247          
248          --color-foreground: 255,255,255;
249          --color-shadow: 18,18,18;
250          --color-button: 255,255,255;
251          --color-button-text: 255,255,255;
252          --color-secondary-button: 18,18,18;
253          --color-secondary-button-text: 18,18,18;
254          --color-link: 18,18,18;
255          --color-badge-foreground: 255,255,255;
256          --color-badge-background: 18,18,18;
257          --color-badge-border: 255,255,255;
258          --payment-terms-background-color: rgb(18 18 18);
259        }
260      
261        
262        .color-scheme-720e2e72-967a-4ac1-aa51-633b7d9ff9e3 {
263          --color-background: 185,234,153;
264          
265            --gradient-background: #b9ea99;
266          
267          --color-foreground: 18,18,18;
268          --color-shadow: 18,18,18;
269          --color-button: 185,234,153;
270          --color-button-text: 185,234,153;
271          --color-secondary-button: 185,234,153;
272          --color-secondary-button-text: 18,18,18;
273          --color-link: 18,18,18;
274          --color-badge-foreground: 18,18,18;
275          --color-badge-background: 185,234,153;
276          --color-badge-border: 18,18,18;
277          --payment-terms-background-color: rgb(185 234 153);
278        }
279      
280        
281        .color-scheme-a7ae43f3-4401-4c19-abd9-68610e102a83 {
282          --color-background: 255,145,77;
283          
284            --gradient-background: #ff914d;
285          
286          --color-foreground: 18,18,18;
287          --color-shadow: 255,255,255;
288          --color-button: 255,255,255;
289          --color-button-text: 255,255,255;
290          --color-secondary-button: 255,145,77;
291          --color-secondary-button-text: 255,255,255;
292          --color-link: 255,255,255;
293          --color-badge-foreground: 18,18,18;
294          --color-badge-background: 255,145,77;
295          --color-badge-border: 18,18,18;
296          --payment-terms-background-color: rgb(255 145 77);
297        }
298      
299        
300        .color-scheme-b3348d90-cedc-48d5-857e-3d0bcd038c27 {
301          --color-background: 8,8,8;
302          
303            --gradient-background: #080808;
304          
305          --color-foreground: 255,255,255;
306          --color-shadow: 18,18,18;
307          --color-button: 94,193,31;
308          --color-button-text: 255,255,255;
309          --color-secondary-button: 8,8,8;
310          --color-secondary-button-text: 18,18,18;
311          --color-link: 18,18,18;
312          --color-badge-foreground: 255,255,255;
313          --color-badge-background: 8,8,8;
314          --color-badge-border: 255,255,255;
315          --payment-terms-background-color: rgb(8 8 8);
316        }
317      
318        
319        .color-scheme-e14f7e9d-d6df-4a61-9f92-96cddbace30c {
320          --color-background: 140,82,255;
321          
322            --gradient-background: #8c52ff;
323          
324          --color-foreground: 255,255,255;
325          --color-shadow: 18,18,18;
326          --color-button: 255,255,255;
327          --color-button-text: 18,18,18;
328          --color-secondary-button: 140,82,255;
329          --color-secondary-button-text: 18,18,18;
330          --color-link: 18,18,18;
331          --color-badge-foreground: 255,255,255;
332          --color-badge-background: 140,82,255;
333          --color-badge-border: 255,255,255;
334          --payment-terms-background-color: rgb(140 82 255);
335        }
336      
337
338      body, .color-background-1, .color-background-2, .color-inverse, .color-accent-1, .color-accent-2, .color-scheme-2bbee085-e3ce-49f4-8eba-bd31d571ab49, .color-scheme-720e2e72-967a-4ac1-aa51-633b7d9ff9e3, .color-scheme-a7ae43f3-4401-4c19-abd9-68610e102a83, .color-scheme-b3348d90-cedc-48d5-857e-3d0bcd038c27, .color-scheme-e14f7e9d-d6df-4a61-9f92-96cddbace30c {
339        color: rgba(var(--color-foreground), 0.75);
340        background-color: rgb(var(--color-background));
341      }
342
343      :root {
344        --font-body-family: Assistant, sans-serif;
345        --font-body-style: normal;
346        --font-body-weight: 400;
347
348        --font-heading-family: Assistant, sans-serif;
349        --font-heading-style: normal;
350        --font-heading-weight: 400;
351
352        --font-body-scale: 1.0;
353        --font-heading-scale: 1.0;
354        --media-padding: px;
355        --media-border-opacity: 0.05;
356        --media-border-width: 1px;
357        --media-radius: 0px;
358        --media-shadow-opacity: 0.0;
359        --media-shadow-horizontal-offset: 0px;
360        --media-shadow-vertical-offset: 4px;
361        --media-shadow-blur-radius: 5px;
362        --media-shadow-visible: 0;
363
364        --page-width: 120rem;
365        --page-width-margin: 0rem;
366
367        --product-card-image-padding: 0.0rem;
368        --product-card-corner-radius: 0.0rem;
369        --product-card-text-alignment: left;
370        --product-card-border-width: 0.0rem;
371        --product-card-border-opacity: 0.1;
372        --product-card-shadow-opacity: 0.0;
373        --product-card-shadow-visible: 0;
374        --product-card-shadow-horizontal-offset: 0.0rem;
375        --product-card-shadow-vertical-offset: 0.4rem;
376        --product-card-shadow-blur-radius: 0.5rem;
377
378        --collection-card-image-padding: 0.0rem;
379        --collection-card-corner-radius: 0.0rem;
380        --collection-card-text-alignment: left;
381        --collection-card-border-width: 0.0rem;
382        --collection-card-border-opacity: 0.1;
383        --collection-card-shadow-opacity: 0.0;
384        --collection-card-shadow-visible: 0;
385        --collection-card-shadow-horizontal-offset: 0.0rem;
386        --collection-card-shadow-vertical-offset: 0.4rem;
387        --collection-card-shadow-blur-radius: 0.5rem;
388
389        --blog-card-image-padding: 0.0rem;
390        --blog-card-corner-radius: 0.0rem;
391        --blog-card-text-alignment: left;
392        --blog-card-border-width: 0.0rem;
393        --blog-card-border-opacity: 0.1;
394        --blog-card-shadow-opacity: 0.0;
395        --blog-card-shadow-visible: 0;
396        --blog-card-shadow-horizontal-offset: 0.0rem;
397        --blog-card-shadow-vertical-offset: 0.4rem;
398        --blog-card-shadow-blur-radius: 0.5rem;
399
400        --badge-corner-radius: 4.0rem;
401
402        --spacing-sections-desktop: 0px;
403        --spacing-sections-mobile: 0px;
404
405        --grid-desktop-vertical-spacing: 8px;
406        --grid-desktop-horizontal-spacing: 8px;
407        --grid-mobile-vertical-spacing: 4px;
408        --grid-mobile-horizontal-spacing: 4px;
409
410        --text-boxes-border-opacity: 0.1;
411        --text-boxes-border-width: 0px;
412        --text-boxes-radius: 0px;
413        --text-boxes-shadow-opacity: 0.0;
414        --text-boxes-shadow-visible: 0;
415        --text-boxes-shadow-horizontal-offset: 0px;
416        --text-boxes-shadow-vertical-offset: 4px;
417        --text-boxes-shadow-blur-radius: 5px;
418
419        --buttons-radius: 0px;
420        --buttons-radius-outset: 0px;
421        --buttons-border-width: 0px;
422        --buttons-border-opacity: 1.0;
423        --buttons-shadow-opacity: 0.0;
424        --buttons-shadow-visible: 0;
425        --buttons-shadow-horizontal-offset: 0px;
426        --buttons-shadow-vertical-offset: 4px;
427        --buttons-shadow-blur-radius: 5px;
428        --buttons-border-offset: 0px;
429
430        --inputs-radius: 0px;
431        --inputs-border-width: 1px;
432        --inputs-border-opacity: 0.55;
433        --inputs-shadow-opacity: 0.0;
434        --inputs-shadow-horizontal-offset: 0px;
435        --inputs-margin-offset: 0px;
436        --inputs-shadow-vertical-offset: 4px;
437        --inputs-shadow-blur-radius: 5px;
438        --inputs-radius-outset: 0px;
439
440        --variant-pills-radius: 40px;
441        --variant-pills-border-width: 1px;
442        --variant-pills-border-opacity: 0.55;
443        --variant-pills-shadow-opacity: 0.0;
444        --variant-pills-shadow-horizontal-offset: 0px;
445        --variant-pills-shadow-vertical-offset: 4px;
446        --variant-pills-shadow-blur-radius: 5px;
447      }
448    </style>
449
450      <link rel="preload" as="font" href="//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.9120912a469cad1cc292572851508ca49d12e768.woff2" type="font/woff2" crossorigin>
451      
452
453      <link rel="preload" as="font" href="//balkonkraftwerk-express.de/cdn/fonts/assistant/assistant_n4.9120912a469cad1cc292572851508ca49d12e768.woff2" type="font/woff2" crossorigin>
454      
455<link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/section-password.css?v=33879197286244898171778255914" rel="stylesheet" type="text/css" media="all" />
456    <link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/base.css?v=16534392784228263581778255914" rel="stylesheet" type="text/css" media="all" />
457    <link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/component-list-social.css?v=35792976012981934991778255914" rel="stylesheet" type="text/css" media="all" />
458
459    
459<script src="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/global.js?v=136628361274817707361778255914" defer="defer"></script>
459
460    
460<script src="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/details-modal.js?v=25581673532751508451778255914" defer="defer"></script>
460
461    
461<script src="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/password-modal.js?v=79398572782218654001778255914" defer="defer"></script>
461
462  <!-- BEGIN app block: shopify://apps/klaviyo-email-marketing-sms/blocks/klaviyo-onsite-embed/2632fe16-c075-4321-a88b-50b567f42507 -->
463
464
465
466
467
468
469
470
471
472
473
474
475  
475<script async src="https://static.klaviyo.com/onsite/js/UnxcSC/klaviyo.js?company_id=UnxcSC"></script>
475
476  
476<script>!function(){if(!window.klaviyo){window._klOnsite=window._klOnsite||[];try{window.klaviyo=new Proxy({},{get:function(n,i){return"push"===i?function(){var n;(n=window._klOnsite).push.apply(n,arguments)}:function(){for(var n=arguments.length,o=new Array(n),w=0;w<n;w++)o[w]=arguments[w];var t="function"==typeof o[o.length-1]?o.pop():void 0,e=new Promise((function(n){window._klOnsite.push([i].concat(o,[function(i){t&&t(i),n(i)}]))}));return e}}})}catch(n){window.klaviyo=window.klaviyo||[],window.klaviyo.push=function(){var n;(n=window._klOnsite).push.apply(n,arguments)}}}}();</script>
476
477
478  
479
480
481
482
483  
483<script>
484    window.klaviyoReviewsProductDesignMode = false
485  </script>
485
486
487
488
489
490
491
492
493
494
495<!-- END app block --><link href="https://monorail-edge.shopifysvc.com" rel="dns-prefetch">
496<script>(function(){if ("sendBeacon" in navigator && "performance" in window) {try {var session_token_from_headers = performance.getEntriesByType('navigation')[0].serverTiming.find(x => x.name == '_s').description;} catch {var session_token_from_headers = undefined;}var session_cookie_matches = document.cookie.match(/_shopify_s=([^;]*)/);var session_token_from_cookie = session_cookie_matches && session_cookie_matches.length === 2 ? session_cookie_matches[1] : "";var session_token = session_token_from_headers || session_token_from_cookie || "";function handle_abandonment_event(e) {var entries = performance.getEntries().filter(function(entry) {return /monorail-edge.shopifysvc.com/.test(entry.name);});if (!window.abandonment_tracked && entries.length === 0) {window.abandonment_tracked = true;var currentMs = Date.now();var navigation_start = performance.timing.navigationStart;var payload = {shop_id: 55579017562,url: window.location.href,navigation_start,duration: currentMs - navigation_start,session_token,page_type: "password"};window.navigator.sendBeacon("https://monorail-edge.shopifysvc.com/v1/produce", JSON.stringify({schema_id: "online_store_buyer_site_abandonment/1.1",payload: payload,metadata: {event_created_at_ms: currentMs,event_sent_at_ms: currentMs}}));}}window.addEventListener('pagehide', handle_abandonment_event);}}());</script>
vendor: 1 bytes, line 496
496
497<script>
498  window.__TREKKIE_SHIM_QUEUE = window.__TREKKIE_SHIM_QUEUE || [];
499</script>
vendor: 1 bytes, line 499
499
500<script>(function(){var wpmLoader=function(){"use strict";var e=/Googlebot|Storebot-Google|bingbot|Baiduspider|YandexBot|DuckDuckBot|Slurp|facebookexternalhit|Twitterbot|LinkedInBot|Applebot|AdsBot-Google|Mediapartners-Google|APIs-Google|PetalBot|SemrushBot|AhrefsBot|MJ12bot|DotBot|Acunetix|PerplexityBot|Perplexity-User/i,t=/bytedance/i;function i(){try{var e=document.cookie;if(!e||"string"!=typeof e)return;for(var t=0,i=e.split(";");t<i.length;t++){var n=i[t],r=n.indexOf("=");if(-1!==r){var o=n.slice(0,r).trim();if(o){var a=void 0;try{a=decodeURIComponent(o)}catch(e){a=o}if("_shopify_s"===a){var d=n.slice(r+1).trim();try{return decodeURIComponent(d)}catch(e){return d}}}}}return}catch(e){return}}function n(e){try{"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn(e)}catch(e){}}function r(e,t){return"string"==typeof e&&e.length>0&&e.length<=t?e:void 0}function o(e){var t;switch(null==(t=null==e?void 0:e.navigation)?void 0:t.type){case 0:return"navigate";case 1:return"reload";case 2:return"back_forward";default:return}}function a(){var e,t,i;try{var n=null==(i=null==(t=null==(e=self.ShopifyAnalytics)?void 0:e.lib)?void 0:t.trekkie)?void 0:i.state;return"awaiting-consent"===n||"initialized"===n?n:void 0}catch(e){return}}return function(d,s,u,l){var c=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};try{var p=c.trekkieShim;!0!==p&&"true"!==p||null!=window.__TREKKIE_SHIM_QUEUE||(window.__TREKKIE_SHIM_QUEUE=[])}catch(e){}var f,v,h,y,g=(v=(f={modern:/Edge?\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Firefox\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Chrom(ium|e)\/(9{2}|\d{3,})\.\d+(\.\d+|)|(Maci|X1{2}).+ Version\/(15\.\d+|(1[6-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(9{2}|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(15[._]\d+|(1[6-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|SamsungBrowser\/([2-9]\d|\d{3,})\.\d+/,legacy:/Edge?\/(1[6-9]|[2-9]\d|\d{3,})\.\d+(\.\d+|)|Firefox\/(5[4-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)|Chrom(ium|e)\/(5[1-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)([\d.]+$|.*Safari\/(?![\d.]+ Edge\/[\d.]+$))|(Maci|X1{2}).+ Version\/(10\.\d+|(1[1-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(3[89]|[4-9]\d|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(10[._]\d+|(1[1-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Mobile Safari.+OPR\/([89]\d|\d{3,})\.\d+\.\d+|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+(UC? ?Browser|UCWEB|U3)[ /]?(15\.([5-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})\.\d+)\.\d+|SamsungBrowser\/(5\.\d+|([6-9]|\d{2,})\.\d+)|Android.+MQ{2}Browser\/(14(\.(9|\d{2,})|)|(1[5-9]|[2-9]\d|\d{3,})(\.\d+|))(\.\d+|)|K[Aa][Ii]OS\/(3\.\d+|([4-9]|\d{2,})\.\d+)(\.\d+|)/}).modern,h=f.legacy,(y=navigator.userAgent).match(e)?"bot":y.match(v)?"modern":y.match(h)?"legacy":y.match(t)?"bot":"unknown"),m=function(e){var t,i,n=r(e,128);try{var a=window.performance,d=null==(t=null==a?void 0:a.getEntriesByType)?void 0:t.call(a,"navigation")[0];if(!d)return{requestId:n,navigationType:o(a)};var s="type"in d?r(d.type,64):void 0,u="serverTiming"in d&&Array.isArray(d.serverTiming)?d.serverTiming:[];return{requestId:null!=n?n:r(null==(i=u.find(function(e){return"requestID"===e.name}))?void 0:i.description,128),navigationType:s}}catch(e){return{requestId:n}}}(c.requestId),w=function(e){var t=e.version,r=e.browserTarget,o=e.surface,a=e.shopId,d=e.monorailEndpoint,s=window.location.href;return{emit:function(e){var u=e.status,l=e.errorMsg,c=e.failureReason,p=e.useKeepaliveFallback,f=void 0!==p&&p,v=e.navigationType,h=e.pagehidePersisted,y=e.requestId,g=e.trekkieState;if(d){var m,w;try{var b=(new Date).getTime();m=JSON.stringify({metadata:{event_sent_at_ms:b},events:[{schema_id:"web_pixels_manager_load/3.3",payload:{version:t,bundle_target:r,page_url:s,status:u,surface:o,error_msg:l,failure_reason:c,navigation_type:v,pagehide_persisted:h,request_id:y,trekkie_state:g,shop_id:a,visit_token:i()},metadata:{event_created_at_ms:b}}]})}catch(e){return}try{if("function"==typeof window.navigator.sendBeacon&&-1===(w=window.navigator.userAgent).indexOf("iPhone; CPU iPhone OS 12_")&&-1===w.indexOf("iPad; CPU OS 12_")&&-1===w.indexOf("iPod touch; CPU iPhone OS 12_")&&window.navigator.sendBeacon.bind(window.navigator)(d,m))return}catch(e){}if(f)try{"function"==typeof window.fetch&&window.fetch(d,{method:"POST",headers:{"Content-Type":"text/plain"},body:m,keepalive:!0}
500).catch(function(){})}catch(e){}else try{var _=new XMLHttpRequest;_.open("POST",d,!0),_.setRequestHeader("Content-Type","text/plain"),_.send(m)}catch(e){n("[Web Pixels Manager] Got an unhandled error while logging to Monorail.")}}else n("[Web Pixels Manager] No Monorail endpoint provided, skipping logging.")}}}({version:u,browserTarget:g,surface:d.surface,shopId:d.shopId,monorailEndpoint:d.monorailEndpoint});if(Boolean(null==(_=null==(b=window.Shopify)?void 0:b.analytics)?void 0:_.replayQueue))w.emit({status:"setup-skipped",errorMsg:"replay queue already initialized."});else{var b,_;w.emit({status:"setup-started"}),window.Shopify=window.Shopify||{};var S=window.Shopify;S.analytics=S.analytics||{};var P=S.analytics;P.replayQueue=[],P.publish=function(e,t,i){return P.replayQueue.push([e,t,i]),!0};try{self.performance.mark("wpm:start")}catch(e){}var k,C="modern"===g?"modern":"legacy",E=(null!=l?l:{modern:"",legacy:""})[C],I=[(k={baseUrl:s,hashVersion:u,buildTarget:C}).baseUrl,"/wpm","/b",k.hashVersion,"modern"===k.buildTarget?"m":"l",".js"].join(""),O=!1,T=!1;try{c.browserTarget=g,function(){O=!0;try{window.addEventListener("pagehide",M)}catch(e){O=!1}}(),R(function(){try{R(x)}catch(e){D(e)}}),w.emit({status:"loading",requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()})}catch(e){D(e)}}function U(){var e;if(q(),!function(){var e,t;return Boolean(null==(t=null==(e=window.Shopify)?void 0:e.analytics)?void 0:t.initialized)}()){var t,i,n;try{if("function"!=typeof(null==(e=window.webPixelsManager)?void 0:e.init))return void A();if(!(null!==(n=i=t=window.webPixelsManager.init(d))&&"function"!=typeof n&&Object(n)===n&&"publish"in i&&"function"==typeof i.publish&&"publishCustomEvent"in i&&"function"==typeof i.publishCustomEvent&&"visitor"in i&&"function"==typeof i.visitor))return void A()}catch(e){return void A(e)}var r=window.Shopify.analytics;r.replayQueue.forEach(function(e){var i=e[0],n=e[1],r=e[2];t.publishCustomEvent(i,n,r)}),r.replayQueue=[],r.publish=t.publishCustomEvent,r.visitor=t.visitor,r.initialized=!0}}function A(e){B("manager_api_unavailable",void 0===e?void 0:Q(e))}function x(){B("script_load_failed","".concat(I," has failed to load"))}function B(e,t){T||(T=!0,q(),w.emit({status:"failed",errorMsg:t,failureReason:e,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function M(e){O&&(q(),w.emit({status:"pagehide-while-loading",useKeepaliveFallback:!0,pagehidePersisted:e.persisted,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function q(){O=!1;try{window.removeEventListener("pagehide",M)}catch(e){}}function R(e){var t;!function(e){var t=e.src,i=e.async,n=void 0===i||i,r=e.onload,o=e.onerror,a=e.sri,d=e.scriptDataAttributes,s=void 0===d?{}:d,u=document.createElement("script"),l=document.querySelector("head"),c=document.querySelector("body");if(u.async=n,u.src=t,a&&(u.integrity=a,u.crossOrigin="anonymous"),s)for(var p in s)if(Object.prototype.hasOwnProperty.call(s,p))try{u.dataset[p]=String(s[p])}catch(e){}if(r&&u.addEventListener("load",r),o&&u.addEventListener("error",o),l)l.appendChild(u);else{if(!c)throw new Error("Did not find a head or body element to append the script");c.appendChild(u)}}({src:I,async:!0,onload:U,onerror:e,sri:(t=E,"string"==typeof t&&/^sha384-[A-Za-z0-9+/=]+$/.test(t)?E:""),scriptDataAttributes:c})}function D(e){B("script_append_failed",Q(e))}function Q(e){return e instanceof Error?e.message:"Unknown error"}}}();wpmLoader({shopId: 55579017562,storefrontBaseUrl: "https://balkonkraftwerk-express.de",extensionsBaseUrl: "https://extensions.shopifycdn.com/cdn/shopifycloud/web-pixels-manager",monorailEndpoint: "https://balkonkraftwerk-express.de/.well-known/shopify/monorail/unstable/produce_batch",surface: "storefront-renderer",enabledBetaFlags: ["4c64608a","16072cab"],webPixelsConfigList: [{"id":"957907290","configuration":"{\"config\":\"{\\\"google_tag_ids\\\":[\\\"G-1685M1KE7B\\\",\\\"GT-MRQK5B5K\\\"],\\\"gtag_events\\\":[{\\\"type\\\":\\\"begin_checkout\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/1un6CNGpk-0aEIqLnL4p\\\"]},{\\\"type\\\":\\\"search\\\",\\\"action_label\\\":[\\\"G-1685M1KE
5007B\\\",\\\"AW-11136337290\\\/bCeXCMupk-0aEIqLnL4p\\\"]},{\\\"type\\\":\\\"remove_from_cart\\\",\\\"action_label\\\":\\\"G-1685M1KE7B\\\"},{\\\"type\\\":\\\"view_item\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/vA6uCMipk-0aEIqLnL4p\\\",\\\"MC-3MGF44JG35\\\"]},{\\\"type\\\":\\\"add_shipping_info\\\",\\\"action_label\\\":\\\"G-1685M1KE7B\\\"},{\\\"type\\\":\\\"purchase\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/bi5VCMqok-0aEIqLnL4p\\\",\\\"MC-3MGF44JG35\\\",\\\"AW-11136337290\\\/cJx4CLzr0a4ZEIqLnL4p\\\"]},{\\\"type\\\":\\\"page_view\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/KY-_CM2ok-0aEIqLnL4p\\\",\\\"MC-3MGF44JG35\\\"]},{\\\"type\\\":\\\"view_item_list\\\",\\\"action_label\\\":\\\"G-1685M1KE7B\\\"},{\\\"type\\\":\\\"add_payment_info\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/tVS0CPKpk-0aEIqLnL4p\\\"]},{\\\"type\\\":\\\"add_to_cart\\\",\\\"action_label\\\":[\\\"G-1685M1KE7B\\\",\\\"AW-11136337290\\\/q43dCM6pk-0aEIqLnL4p\\\"]},{\\\"type\\\":\\\"view_cart\\\",\\\"action_label\\\":\\\"G-1685M1KE7B\\\"}],\\\"enable_monitoring_mode\\\":false}\"}","eventPayloadVersion":"v1","runtimeContext":"OPEN","scriptVersion":"a3321ca85cf5aaf6b57585fcd8d67b3a","type":"APP","apiClientId":1780363,"privacyPurposes":[],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted","enabledFlags":["9a3ed68a"]},{"id":"345506138","configuration":"{\"pixel_id\":\"1440502810142375\",\"pixel_type\":\"facebook_pixel\",\"metaapp_system_user_token\":\"-\"}","eventPayloadVersion":"v1","runtimeContext":"OPEN","scriptVersion":"bd2f978c17a94bbb8a74d43de2165dc5","type":"APP","apiClientId":2329312,"privacyPurposes":["ANALYTICS","MARKETING","SALE_OF_DATA"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted","enabledFlags":["9a3ed68a"]},{"id":"284492122","eventPayloadVersion":"1","runtimeContext":"LAX","scriptVersion":"1","type":"CUSTOM","privacyPurposes":[],"name":"Klar!"},{"id":"shopify-app-pixel","configuration":"{}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"APP","privacyPurposes":["ANALYTICS","MARKETING"]},{"id":"shopify-custom-pixel","eventPayloadVersion":"v1","runtimeContext":"LAX","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"CUSTOM","privacyPurposes":["ANALYTICS","MARKETING"]}],isMerchantRequest: false,initData: {"shop":{"name":"Balkonkraftwerk-Express","paymentSettings":{"currencyCode":"EUR"},"myshopifyDomain":"e94e42.myshopify.com","countryCode":"DE","storefrontUrl":"https:\/\/balkonkraftwerk-express.de"},"customer":null,"cart":null,"checkout":null,"productVariants":[],"products":[],"purchasingCompany":null},},"https://balkonkraftwerk-express.de/cdn","7ec887c8w14f9f074p854094e1m1370c602",{"modern":"","legacy":""},{"trekkieShim":true,"agentContext":true,"apiClientId":"580111","facebookCapiEnabled":"true","themeId":"193346863450","themeStoreId":"887","themePublished":"true","eventMetadataId":"9291e214-3418-4053-b183-32f60aef3746","pageType":"password","shopId":"55579017562","storefrontBaseUrl":"https:\/\/balkonkraftwerk-express.de","extensionBaseUrl":"https:\/\/extensions.shopifycdn.com\/cdn\/shopifycloud\/web-pixels-manager","surface":"storefront-renderer","enabledBetaFlags":"[\"4c64608a\", \"16072cab\"]","isMerchantRequest":"false","hashVersion":"7ec887c8w14f9f074p854094e1m1370c602","publish":"custom","events":"[[\"page_viewed\",{}]]"});})();</script>
500<script>
501  window.ShopifyAnalytics = window.ShopifyAnalytics || {};
502  window.ShopifyAnalytics.meta = window.ShopifyAnalytics.meta || {};
503  window.ShopifyAnalytics.meta.currency = 'EUR';
504  var meta = {"page":{"pageType":"password","requestId":"5823bc87-814a-4b96-beff-79d5c90e35af-1791586216"}};
505  for (var attr in meta) {
506    window.ShopifyAnalytics.meta[attr] = meta[attr];
507  }
508</script>
vendor: 1 bytes, line 508
508
509<script class="analytics">
510  (function () {
511    var customDocumentWrite = function(content) {
512      var jquery = null;
513
514      if (window.jQuery) {
515        jquery = window.jQuery;
516      } else if (window.Checkout && window.Checkout.$) {
517        jquery = window.Checkout.$;
518      }
519
520      if (jquery) {
521        jquery('body').append(content);
522      }
523    };
524
525    var hasLoggedConversion = function(token) {
526      if (token) {
527        return document.cookie.indexOf('loggedConversion=' + token) !== -1;
528      }
529      return false;
530    }
531
532    var setCookieIfConversion = function(token) {
533      if (token) {
534        var twoMonthsFromNow = new Date(Date.now());
535        twoMonthsFromNow.setMonth(twoMonthsFromNow.getMonth() + 2);
536
537        document.cookie = 'loggedConversion=' + token + '; expires=' + twoMonthsFromNow;
538      }
539    }
540
541    var trekkie = window.ShopifyAnalytics.lib = window.trekkie = window.trekkie || [];
542    window.ShopifyAnalytics.lib.trekkie = window.trekkie;
543    if (trekkie.integrations) {
544      return;
545    }
546    trekkie.methods = [
547      'identify',
548      'page',
549      'ready',
550      'track',
551      'trackForm',
552      'trackLink'
553    ];
554    trekkie.factory = function(method) {
555      return function() {
556        var args = Array.prototype.slice.call(arguments);
557        args.unshift(method);
558        trekkie.push(args);
559        if (method == 'track' || method == 'page') {
560          var pageUrl;
561          try {
562            pageUrl = window.location.href;
563          } catch (e) {}
564          var pageReferrer;
565          try {
566            pageReferrer = document.referrer;
567          } catch (e) {}
568          try {
569            if (window.__TREKKIE_SHIM_QUEUE == null) {
570              window.__TREKKIE_SHIM_QUEUE = [];
571            }
572            window.__TREKKIE_SHIM_QUEUE.push({
573              from: 'trekkie-stub',
574              method: method,
575              args: args.slice(1),
576              pageContext: {
577                url: pageUrl,
578                referrer: pageReferrer
579              }
580            });
581          } catch (e) {
582            // no-op
583          }
584        }
585        return trekkie;
586      };
587    };
588    for (var i = 0; i < trekkie.methods.length; i++) {
589      var key = trekkie.methods[i];
590      trekkie[key] = trekkie.factory(key);
591    }
592    trekkie.load = function(config) {
593      trekkie.config = config || {};
594      trekkie.config.initialDocumentCookie = document.cookie;
595      var first = document.getElementsByTagName('script')[0];
596var script = document.createElement('script');
597script.type = 'text/javascript';
598script.onerror = function(e) {
599  var scriptFallback = document.createElement('script');
600  scriptFallback.type = 'text/javascript';
601  scriptFallback.onerror = function(error) {
602          var Monorail = {
603      produce: function produce(monorailDomain, schemaId, payload) {
604        var currentMs = new Date().getTime();
605        var event = {
606          schema_id: schemaId,
607          payload: payload,
608          metadata: {
609            event_created_at_ms: currentMs,
610            event_sent_at_ms: currentMs
611          }
612        };
613        return Monorail.sendRequest("https://" + monorailDomain + "/v1/produce", JSON.stringify(event));
614      },
615      sendRequest: function sendRequest(endpointUrl, payload) {
616        // Try the sendBeacon API
617        if (window && window.navigator && typeof window.navigator.sendBeacon === 'function' && typeof window.Blob === 'function' && !Monorail.isIos12()) {
618          var blobData = new window.Blob([payload], {
619            type: 'text/plain'
620          });
621
622          if (window.navigator.sendBeacon(endpointUrl, blobData)) {
623            return true;
624          } // sendBeacon was not successful
625
626        } // XHR beacon
627
628        var xhr = new XMLHttpRequest();
629
630        try {
631          xhr.open('POST', endpointUrl);
632          xhr.setRequestHeader('Content-Type', 'text/plain');
633          xhr.send(payload);
634        } catch (e) {
635          console.log(e);
636        }
637
638        return false;
639      },
640      isIos12: function isIos12() {
641        return window.navigator.userAgent.lastIndexOf('iPhone; CPU iPhone OS 12_') !== -1 || window.navigator.userAgent.lastIndexOf('iPad; CPU OS 12_') !== -1;
642      }
643    };
644    Monorail.produce('monorail-edge.shopifysvc.com',
645      'trekkie_storefront_load_errors/1.1',
646      {shop_id: 55579017562,
647      theme_id: 193346863450,
648      app_name: "storefront",
649      context_url: window.location.href,
650      source_url: "//balkonkraftwerk-express.de/cdn/s/trekkie.storefront.51e69540e15035ae012ec8cc42e8f9cd792233a0.min.js"});
651
652  };
653  scriptFallback.async = true;
654  scriptFallback.src = '//balkonkraftwerk-express.de/cdn/s/trekkie.storefront.51e69540e15035ae012ec8cc42e8f9cd792233a0.min.js';
655  first.parentNode.insertBefore(scriptFallback, first);
656};
657script.async = true;
658script.src = '//balkonkraftwerk-express.de/cdn/s/trekkie.storefront.51e69540e15035ae012ec8cc42e8f9cd792233a0.min.js';
659first.parentNode.insertBefore(script, first);
660
661    };
662    trekkie.load(
663      {"Trekkie":{"appName":"storefront","development":false,"defaultAttributes":{"shopId":55579017562,"isMerchantRequest":null,"themeId":193346863450,"themeCityHash":"2785675698912787895","contentLanguage":"de","currency":"EUR","eventMetadataId":"9291e214-3418-4053-b183-32f60aef3746"},"isServerSideCookieWritingEnabled":true,"monorailRegion":"shop_domain","enabledBetaFlags":["764d78cb","4c64608a"]},"Session Attribution":{},"S2S":{"facebookCapiEnabled":true,"source":"trekkie-storefront-renderer","apiClientId":580111}}
664    );
665
666    var loaded = false;
667    trekkie.ready(function() {
668      if (loaded) return;
669      loaded = true;
670
671      window.ShopifyAnalytics.lib = window.trekkie;
672
673      var originalDocumentWrite = document.write;
674      document.write = customDocumentWrite;
675      try { window.ShopifyAnalytics.merchantGoogleAnalytics.call(this); } catch(error) {};
676      document.write = originalDocumentWrite;
677
678      var match = window.location.pathname.match(/checkouts\/(.+)\/(thank_you|post_purchase)/)
679      var token = match? match[1]: undefined;
680      if (!hasLoggedConversion(token)) {
681        setCookieIfConversion(token);
682        
683      }
684    });
685
686    window.ShopifyAnalytics.lib.page(null,{"pageType":"password","requestId":"5823bc87-814a-4b96-beff-79d5c90e35af-1791586216","shopifyEmitted":true});
687
688    var eventsListenerScript = document.createElement('script');
689    eventsListenerScript.async = true;
690    eventsListenerScript.src = "//balkonkraftwerk-express.de/cdn/shopifycloud/storefront/assets/shop_events_listener-4e26a9ce.js";
691    document.getElementsByTagName('head')[0].appendChild(eventsListenerScript);
692})();</script>
vendor: 1 bytes, line 692
692
693<script
694  defer
695  src="https://balkonkraftwerk-express.de/cdn/shopifycloud/perf-kit/shopify-perf-kit-3.10.1.min.js"
696  data-application="storefront-renderer"
697  data-shop-id="55579017562"
698  data-render-region="gcp-europe-west4"
699  data-page-type="password"
700  data-theme-instance-id="193346863450"
701  data-theme-name="Dawn"
702  data-theme-version="14.0.0"
703  data-monorail-region="shop_domain"
704  data-resource-timing-sampling-rate="10"
705  data-shs="true"
706  data-shs-beacon="true"
707  data-shs-export-with-fetch="true"
708  data-shs-logs-sample-rate="1"
709  data-shs-beacon-endpoint="https://balkonkraftwerk-express.de/api/collect"
710></script>
710
711<meta name="shopify-y" content="296bd508-3bf7-438b-8c59-f7be3c4d8688" data-expiration="1823143817000"><meta name="shopify-s" content="83d7f2b8-2b2e-415c-ac51-354eb3b00862" data-expiration="1791588017000">
712</head>
713
714  <body class="password gradient">
715    <a class="skip-to-content-link button visually-hidden" href="#MainContent">
716      Direkt zum Inhalt
717    </a>
718
719    <div id="shopify-section-main-password-header" class="shopify-section"><style type="text/css">
720  .password-logo {
721    max-width: 160px;
722  }
723</style>
724
725<div class="color-background-1 gradient">
726  <div class="password-header"><img src="//balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=500" alt="Balkonkraftwerk-Express" srcset="//balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=50 50w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=100 100w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=150 150w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=200 200w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=250 250w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=300 300w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=400 400w, //balkonkraftwerk-express.de/cdn/shop/files/BKE-logo-high.jpg?v=1691081304&amp;width=500 500w" width="160" height="75.66632337796086" class="password-logo">
727<password-modal>
728      <details class="password-modal modal">
729        <summary class="modal__toggle" aria-haspopup="dialog">
730          <div class="modal__toggle-open password-link link underlined-link">
731            <svg aria-hidden="true" focusable="false" class="icon icon-padlock" viewBox="0 0 16 21" fill="none">
732  <path fill-rule="evenodd" d="M5.03 1.79A3.73 3.73 0 018 .5c1.28 0 2.28.48 2.97 1.29.67.8 1 1.87 1.03 3V7.5h3c.28 0 .5.22.5.5v12a.5.5 0 01-.5.5H1a.5.5 0 01-.5-.5V8c0-.28.22-.5.5-.5h3V4.8c0-1.1.36-2.15 1.03-3.01zM11 6.4v1.09H5V4.82c.03-.99.31-1.82.8-2.4A2.75 2.75 0 018 1.49c1.01 0 1.73.37 2.2.93.49.58.77 1.41.8 2.4V6.4zM1.5 8.49v11h13v-11h-13zm6.51 2.5a1.5 1.5 0 00-.7 2.82v2.5a.68.68 0 001.36 0v-2.47A1.5 1.5 0 008 11l.01-.01z" clip-rule="evenodd" fill="currentColor" />
733</svg>
734
735            Mit Passwort betreten
736          </div>
737          <div class="modal__toggle-close" aria-hidden="true">
738            <svg
739  xmlns="http://www.w3.org/2000/svg"
740  aria-hidden="true"
741  focusable="false"
742  class="icon icon-close"
743  fill="none"
744  viewBox="0 0 18 17"
745>
746  <path d="M.865 15.978a.5.5 0 00.707.707l7.433-7.431 7.579 7.282a.501.501 0 00.846-.37.5.5 0 00-.153-.351L9.712 8.546l7.417-7.416a.5.5 0 10-.707-.708L8.991 7.853 1.413.573a.5.5 0 10-.693.72l7.563 7.268-7.418 7.417z" fill="currentColor">
747</svg>
748
749          </div>
750        </summary>
751        <div
752          class="modal__content"
753          role="dialog"
754          aria-labelledby="DialogHeading"
755          aria-modal="true"
756        >
757          <div class="password-modal__content" tabindex="-1">
758            <button type="button" class="modal__close-button link" aria-label="Schließen">
759              <svg
760  xmlns="http://www.w3.org/2000/svg"
761  aria-hidden="true"
762  focusable="false"
763  class="icon icon-close"
764  fill="none"
765  viewBox="0 0 18 17"
766>
767  <path d="M.865 15.978a.5.5 0 00.707.707l7.433-7.431 7.579 7.282a.501.501 0 00.846-.37.5.5 0 00-.153-.351L9.712 8.546l7.417-7.416a.5.5 0 10-.707-.708L8.991 7.853 1.413.573a.5.5 0 10-.693.72l7.563 7.268-7.418 7.417z" fill="currentColor">
768</svg>
769
770            </button>
771            <h2 class="password-modal__content-heading" id="DialogHeading">
772              Shop mit Passwort betreten:
773            </h2><form method="post" action="/password" id="login_form" accept-charset="UTF-8" class="password-form"><input type="hidden" name="form_type" value="storefront_password" /><input type="hidden" name="utf8" value="✓" /><div class="password-field field">
774                <input
775                  type="password"
776                  name="password"
777                  id="Password"
778                  class="field__input"
779                  autocomplete="current-password"
780                  placeholder="Dein Passwort"
781                >
782                <label class="field__label" for="Passwort">Dein Passwort</label></div>
783              <button name="commit" class="password-button button button--outline">
784                Eingeben
785              </button></form><small class="password__footer-text">Bist du der Shop-Inhaber? <a href="/admin" class="link underlined-link">Hier einloggen</a></small>
786          </div>
787        </div>
788      </details>
789    </password-modal>
790  </div>
791</div>
792
793<hr>
794</div>
795
796    <main id="MainContent" class="password-main">
797      <section id="shopify-section-template--28298773856602__main" class="shopify-section section"><link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/section-image-banner.css?v=124819179385751388401778255914" rel="stylesheet" type="text/css" media="all" />
798<link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/component-newsletter.css?v=4727253280200485261778255914" rel="stylesheet" type="text/css" media="all" />
799<link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/newsletter-section.css?v=62410470717655853621778255914" rel="stylesheet" type="text/css" media="all" />
800<link href="//balkonkraftwerk-express.de/cdn/shop/t/40/assets/section-email-signup-banner.css?v=77014967447923078771778255914" rel="stylesheet" type="text/css" media="all" />
801<style data-shopify>#Banner-template--28298773856602__main::after {
802    opacity: 0.0;
803  }</style><div
804  id="Banner-template--28298773856602__main"
805  class="email-signup-banner banner banner--content-align-center banner--content-align-mobile-center banner--medium banner--mobile-bottom"
806><div class="banner__media"><svg
807  preserveAspectRatio="xMidYMid slice"
808  aria-hidden="true"
809  focusable="false"
810  class="email-signup-banner-background"
811  version="1.1"
812  id="Layer_1"
813  xmlns="http://www.w3.org/2000/svg"
814  x="0"
815  y="0"
816  viewBox="0 0 2169.3 648"
817  style="enable-background:new 0 0 2169.3 648"
818  xml:space="preserve"
819>
820  <style>.st0,.st4{fill:rgb(var(--color-button))}.st4{opacity:.55;enable-background:new}</style><path class="st0" d="M1791.7 370.7zM1791.7 650.9V370.8h-.1s.1 271.6.1 280.1zM1791.7 370.8s-.1 0 0 0z"/><path d="M1308.6 371.2V216.6L1084.9-.1 861.4 215.8V651h447.2V371.2zm-223.3-248.4c-15 .1-27-12-27.2-26.8-.2-14.8 12-27 26.8-27.2 15-.1 27 12 27.2 26.8v.1c0 14.9-11.9 27-26.8 27.1z" style="opacity:.75;fill:rgb(var(--color-button));enable-background:new"/><path class="st0" d="M501.6 436.9h131c-45.2-4-86.7-22.2-120-49.9-30.9-25.8-54.7-59.9-68.1-98.7-7.8-22.5-12-46.4-12-71.3V0h.5-205.7c2.5.1 5-.2 7.5 0 110.9 10.6 197.7 104.5 197.8 217.8.2 120.4-100.3 218.8-220.9 218.8h-76v213.9h152.1v-.2c.1-117.8 95.9-213.4 213.8-213.4zM861.4 650.4V277.7c-4.8 17.5-11.8 34.2-20.8 50l-1.7 2.8c-6.3 10.8-13.5 20.8-21.5 30.3-.1.2-.4.4-.5.6l-.1.1c-13.5 15.8-29.2 29.6-46.7 40.9-2.9 1.8-5.6 3.6-8.6 5.3-12.8 7.5-26.3 13.6-40.4 18.3-9.5 3.1-19.1 5.6-29 7.4-10.9 1.9-21.9 3.1-33 3.3-1.8 0-3.5.1-5.3.1h-.1v.7c.1 39 7.7 74.9 25.8 106.5 11.4 19.1 25.4 36.5 41.5 51.6 12.7 11.8 26.6 22.4 41.5 31.2.1.1.4.2.5.4 22.7 13.2 48 20.9 73.9 23.1 1.2.1 2.3.2 3.5.2 3.8.2 20.8.4 20.8.4v-.5h.2z"/><path class="st0" d="M651.6 330.4h2.6c25.2-.6 48.5-9.7 66.8-24.5 25.1-20.2 41.2-51.3 41.2-86 0-34.8-16-65.8-41.2-86-17.9-14.5-40.6-23.4-65.1-24.4-1.4 0-2.9-.1-4.3-.1-61.1 0-110.5 49.5-110.5 110.5s49.4 110.5 110.5 110.5z"/><g style="opacity:.55"><path class="st0" d="M1810 371.2c-3.2 0-10.6 0-18.2-.5-3.7-.2-7.5-.6-11-1.1-1.1-.1-2.2-.4-3.2-.5-125.3-15.6-224.1-119.6-229-248.3-.1-1.1-.2-2.3-.4-3.3-11.8 130.3-108.6 234.6-231.7 252-2.6.4-5.3.7-7.9 1v.6c126.6 14 226.7 119.7 239 252.3 0 .2.6.1.7 0 12.4-133.6 114.3-239.9 242.2-252.6h1.2l.2 101.2-.3 179 384.5.1V371l-366.1.2z"/><path class="st0" d="M1792.4 239c5.9.8 11.7 1.2 17.8 1.2 72.4 0 131-58.6 131-131 0-45.6-23.3-85.8-58.6-109.2H1737.7c-.2.1-.4-.1-.6 0-34.9 23.6-57.9 64-57.9 109.2 0 66.3 49.3 121.1 113.2 129.8z"/></g><g style="opacity:.1"><path class="st0" d="M432.6 217.8C432.5 104.5 345.7 10.6 234.8-.1l-99 .1v436.7h76c120.6-.1 221-98.5 220.8-218.9zM1085 68.9c-15 .1-26.9 12.2-26.8 27.2.1 15 12.2 26.9 27.2 26.8 14.8-.1 26.8-12.1 26.8-26.9v-.1c-.2-15.1-12.3-27.2-27.2-27zM763.2 627.2c-.1-.1-.4-.2-.5-.4-15.1-8.9-29-19.4-41.5-31.2-16.2-15.1-30-32.4-41.5-51.6-18.2-31.5-25.7-67.5-25.8-106.5v-.7h-.3v-.1h-152c-118 0-213.7 95.6-213.8 213.6V650.6h552.9c-1.2-.1-2.3-.2-3.5-.2-26.1-2.2-51.3-10-74-23.2zM1882.5-.1s.1-.1 0 0c35.4 23.4 58.7 63.7 58.7 109.2 0 72.4-58.6 131-131 131-6 0-12-.4-17.8-1.2-63.9-8.7-113.2-63.5-113.2-129.8 0-45.2 23-85.7 57.9-109.2.2-.1.4.1.6 0h.2-165.1c-15.8 33.5-24.6 71.7-24.6 111.2v4.9c0 1.7.1 3.5.1 5.1 4.9 128.6 103.7 232.7 229 248.3 1.1.1 2.2.4 3.2.5 3.5.5 7.3.8 11 1.1 7.7.5 276.9.1 276.9.1V-.1h-185.9z"/></g>
820<path class="st0" d="M1308.6 216.6v153.9c2.6-.2 5.1-.6 7.8-1 123.1-17.3 219.9-121.7 231.7-251.8.1 1.1.2 2.3.4 3.3-.1-1.7-.1-3.3-.1-5.1V111c0-39.5 8.9-77.5 24.6-111h-488.1l223.7 216.6zM1791.6 370.8c-127.8 12.8-231 119-243.5 252.6 0 .2-.1.1-.2 0-12.3-132.7-112.7-238.3-239.3-252.3l-.1 279.3v.7h483.1v-.2c.1-8.5 0-280.1 0-280.1z"/><path class="st0" d="M1548.1 623.4c12.4-133.5 115.6-239.8 243.5-252.6h-1.3c-127.9 12.7-229.7 119-242.2 252.6zM2068.7-.1V371h107.2V-.1z"/><path class="st4" d="M135.9-.1C59.6-.1-2.3 61.8-2.3 138.1V649.9l138.2-.4V-.1z"/><g><path class="st0" d="M721.2 134.3c-17.9-14.5-40.6-23.4-65.1-24.4-1.4 0-2.9-.1-4.3-.1-61.1 0-110.5 49.5-110.5 110.5s49.5 110.5 110.5 110.5h2.6c25.2-.6 48.5-9.7 66.8-24.5 25.1-20.2 41.2-51.3 41.2-86s-16.1-65.8-41.2-86z"/><path class="st4" d="M870.4-.1H432.7v217.5c0 24.9 4.2 48.9 12 71.3 13.3 38.8 37.2 72.9 68.1 98.7 33.3 27.8 74.5 45.5 119.9 49.4h21.1s3.7.6 5.5.5c11.1-.2 22.1-1.4 33-3.3 9.8-1.8 19.5-4.3 29-7.4 14-4.7 27.6-10.8 40.4-18.3 2.9-1.7 5.7-3.5 8.6-5.3 17.5-11.4 33.1-25.1 46.7-40.9l.1-.1c.1-.2.4-.4.5-.6 8-9.5 15.2-19.5 21.5-30.3l1.7-2.8c9-15.8 15.9-33.1 20.7-50.6v-62l69-66.6c-37.4-38.5-60.1-91.4-60.1-149.2zM721.2 306.3c-18.3 14.8-41.5 23.9-66.8 24.5h-2.6c-61.1 0-110.5-49.5-110.5-110.5s49.5-110.5 110.5-110.5c1.4 0 2.9 0 4.3.1 24.6 1 47.1 9.9 65.1 24.4 25.1 20.2 41.2 51.3 41.2 86-.1 34.8-16.1 65.8-41.2 86z"/><path class="st0" d="M870.4-.1s0-.1 0 0c0 57.8 22.7 110.8 60 149.2L1084.9-.1s-214.5-.2-214.5 0z"/></g>
821</svg>
822<svg
823  preserveAspectRatio="xMidYMid slice"
824  aria-hidden="true"
825  focusable="false"
826  class="email-signup-banner-background email-signup-banner-background-mobile"
827  id="Layer_1"
828  data-name="Layer 1"
829  xmlns="http://www.w3.org/2000/svg"
830  viewBox="0 0 374.45 238.04"
831>
832  <defs><style>.cls-1{fill:none;}.cls-2,.cls-4,.cls-5{fill:rgb(var(--color-button));;}.cls-3{opacity:0.55;}.cls-4{opacity:0.75;}.cls-5{opacity:0.1;}</style></defs><path class="cls-1" d="M89.5,238c-7.27-1.67-14.13-5.11-20.52-8.82a87.1,87.1,0,0,1-30.36-30.35c-6.72-11.64-9.49-24.91-9.49-39.33H29v0c0,14.42,2.77,27.71,9.49,39.36a87.1,87.1,0,0,0,30.36,30.35c6.39,3.71,13.25,7.15,20.52,8.82h.46Z"/><path class="cls-2" d="M106.58,95.46v-.6a80.39,80.39,0,0,1-9.11,24.62l-.6,1a80,80,0,0,1-25.22,26.36c-1,.67-2.07,1.33-3.14,1.95a78,78,0,0,1-25.42,9.44,80.26,80.26,0,0,1-14,1.26c0,14.42,2.77,27.69,9.49,39.33A87.1,87.1,0,0,0,69,229.17c6.39,3.71,13.25,7.15,20.52,8.82l.31,0H93.7a15.28,15.28,0,0,1,3.38,0,74.24,74.24,0,0,0,10.2,0h-.64Z"/><g class="cls-3"><path class="cls-2" d="M357,118.48A78.88,78.88,0,0,0,346.42,158v0h0v0A78.9,78.9,0,0,0,357,197.68a79.76,79.76,0,0,0,17.46,20.88v-121A79.52,79.52,0,0,0,357,118.48Z"/><path class="cls-2" d="M346.42,0a78.9,78.9,0,0,1-10.56,39.25,79.66,79.66,0,0,1-28.95,29,78.58,78.58,0,0,1-39.17,10.6,78.6,78.6,0,0,1,39.15,10.59A79.23,79.23,0,0,1,346.42,158V78.86a79,79,0,0,1,28-60.49V0Z"/><path class="cls-2" d="M114.22,27.3a79.2,79.2,0,0,1-5-27.3h-79V0H0V53.79a39.51,39.51,0,0,1,29.37-13l.86,0A39.58,39.58,0,0,1,69,78.88c0,.5,0,1,0,1.51A39.62,39.62,0,0,1,0,107v47a78,78,0,0,0,29,5.56v0h.15a80.26,80.26,0,0,0,14-1.26,78,78,0,0,0,25.42-9.44c1.07-.62,2.11-1.28,3.14-1.95a80,80,0,0,0,25.22-26.36l.6-1a80.39,80.39,0,0,0,9.11-24.62V78.57l24.69-24.1h0a79,79,0,0,1-11.41-15.19A79.32,79.32,0,0,1,114.22,27.3Z"/></g><path class="cls-2" d="M357,39.26a79.64,79.64,0,0,1,17.46-20.89h0A79.64,79.64,0,0,0,357,39.26Z"/><path class="cls-2" d="M357,118.46A78.93,78.93,0,0,0,346.42,158v0a79.09,79.09,0,0,1,28-60.44h0A79.64,79.64,0,0,0,357,118.46Z"/><path class="cls-2" d="M357,197.68a78.9,78.9,0,0,1-10.57-39.6v0h0v0a79.06,79.06,0,0,0-78.68-79.14,78.58,78.58,0,0,0,39.17-10.6,79.66,79.66,0,0,0,28.95-29A78.9,78.9,0,0,0,346.42,0c0-.12,0-.23,0-.35H267.37v0H109.28V0h0a79.2,79.2,0,0,0,5,27.3,79.32,79.32,0,0,0,5.63,12,79,79,0,0,0,11.41,15.19L187,0h0l57,55.91h0l23.36,22.93h0l0,0V238h107V218.56A79.76,79.76,0,0,1,357,197.68Z"/><path class="cls-2" d="M29.37,120A39.62,39.62,0,0,0,69,80.39c0-.51,0-1,0-1.51A39.56,39.56,0,0,0,30.23,40.79l-.86,0A39.51,39.51,0,0,0,0,53.79V107A39.52,39.52,0,0,0,29.37,120Z"/><path class="cls-4" d="M94.12,238h2.82A12.66,12.66,0,0,0,94.12,238Z"/><path class="cls-5" d="M38.47,198.87C31.75,187.22,29,173.93,29,159.51A78,78,0,0,1,0,154V238H89.35c-7.27-1.67-14.13-5.11-20.52-8.82A87.1,87.1,0,0,1,38.47,198.87Z"/><path class="cls-4" d="M267.41,78.88l0,0h0L244,55.91h0L187,0h0L131.26,54.46h0l-24.69,24.1V93.82c0-.21.11-.42.15-.6v25.21l0,79V238h1.41l-.91,0H267.41V78.88ZM187.17,44.49A9.88,9.88,0,1,1,197,34.61,9.88,9.88,0,0,1,187.17,44.49Z"/><path class="cls-4" d="M106.78,238h0V197.42l0-79V93.22c0,.18-.1.39-.15.6v1.64L106.64,238h.64l.91,0Z"/><path class="cls-5" d="M357,39.26a78.9,78.9,0,0,0-10.57,39.6V158a79,79,0,0,1,28-60.43V18.37A79.64,79.64,0,0,0,357,39.26Z"/><circle class="cls-5" cx="187.17" cy="34.61" r="9.88"/>
833</svg>
834</div><div class="banner__content banner__content--middle-center page-width">
835    <div class="email-signup-banner__box banner__box newsletter newsletter__wrapper isolate content-container color-background-1 gradient content-container--full-width-mobile"><h2 class="email-signup-banner__heading h1" >
836              Opening soon
837            </h2><div class="newsletter__subheading rte body" >
838              <p>
838Be the first to know when we launch.</p>
839            </div><div >
840              <form method="post" action="/contact#contact_form" id="contact_form" accept-charset="UTF-8" class="newsletter-form"><input type="hidden" name="form_type" value="customer" /><input type="hidden" name="utf8" value="✓" />
841                <input type="hidden" name="contact[tags]" value="newsletter">
842                <div class="newsletter-form__field-wrapper">
843                  <div class="field">
844                    <input
845                      id="NewsletterForm--template--28298773856602__main"
846                      type="email"
847                      name="contact[email]"
848                      class="field__input"
849                      value=""
850                      aria-required="true"
851                      autocorrect="off"
852                      autocapitalize="off"
853                      autocomplete="email"
854                      
855                      placeholder="E-Mail"
856                      required
857                    >
858                    <label class="field__label" for="NewsletterForm--template--28298773856602__main">
859                      E-Mail
860                    </label>
861                    <button
862                      type="submit"
863                      class="newsletter-form__button field__button"
864                      name="commit"
865                      id="Subscribe"
866                      aria-label="Abonnieren"
867                    >
868                      <svg
869  viewBox="0 0 14 10"
870  fill="none"
871  aria-hidden="true"
872  focusable="false"
873  class="icon icon-arrow"
874  xmlns="http://www.w3.org/2000/svg"
875>
876  <path fill-rule="evenodd" clip-rule="evenodd" d="M8.537.808a.5.5 0 01.817-.162l4 4a.5.5 0 010 .708l-4 4a.5.5 0 11-.708-.708L11.793 5.5H1a.5.5 0 010-1h10.793L8.646 1.354a.5.5 0 01-.109-.546z" fill="currentColor">
877</svg>
878
879                    </button>
880                  </div></div></form>
881            </div></div>
882  </div>
883</div>
884
885
886</section>
887    </main>
888    <footer>
889      <div id="shopify-section-main-password-footer" class="shopify-section">
890<hr><div class="password__footer color-background-1 gradient">
891  <ul class="list-social list-unstyled" role="list"></ul>
892  
893  <small class="password__footer-caption password__footer-text">Dieser Shop wird unterstützt von 
894    <a
895      class="shopify-link"
896      href="//www.shopify.com"
897      rel="nofollow"
898      target="_blank"
899      aria-describedby="a11y-new-window-message"
900      aria-label="Shopify"
901    >
902      <svg
903        xmlns="http://www.w3.org/2000/svg"
904        class="icon icon-shopify"
905        viewBox="0 0 150 43"
906        version="1.1"
907        aria-hidden="true"
908      >
909        <path fill="currentColor" d="M33.3,8.9 C33.3,8.9 33.3,8.7 33.2,8.6 C33.1,8.5 33,8.5 33,8.5 L29.6,8.3 L27.5,6.2 C27.4,6.1 27.3,6.1 27.2,6.1 L25.4,42.2 L38,39.5 L33.3,8.9 Z M25.8,5.9 L24.9,6.2 C24.3,4.6 23.6,3.4 22.6,2.7 C21.9,2.2 21.1,2 20.3,2.1 C20.1,1.9 19.9,1.7 19.7,1.5 C18.8,0.8 17.6,0.6 16.1,1.2 C11.8,2.7 10,8.3 9.3,11 L5.5,12.1 C5.5,12.1 4.6,12.3 4.4,12.6 C4.2,12.9 4.1,13.6 4.1,13.6 L0.9,37.9 L24.5,42.3 L26.3,6 C26.1,5.8 25.9,5.9 25.8,5.9 Z M20.1,7.6 L16,8.9 C16.5,6.8 17.6,4.6 19.6,3.8 C20,4.8 20.1,6.3 20.1,7.6 Z M16.6,2.4 C17.5,2.1 18.2,2.1 18.7,2.4 C16,3.6 14.8,6.7 14.3,9.3 L11,10.3 C11.7,7.8 13.3,3.6 16.6,2.4 Z M18.9,20.3 C18.7,20.2 18.5,20.1 18.2,20 C17.9,19.9 17.7,19.8 17.4,19.7 C17.1,19.6 16.8,19.6 16.4,19.5 L15.3,19.5 C15,19.5 14.7,19.6 14.4,19.7 C14.1,19.8 13.9,19.9 13.7,20.1 C13.5,20.3 13.4,20.5 13.3,20.7 C13.2,20.9 13.1,21.2 13.1,21.4 C13.1,21.6 13.1,21.8 13.2,22 C13.3,22.2 13.4,22.4 13.5,22.6 C13.7,22.8 13.9,23 14.1,23.2 C14.3,23.4 14.6,23.6 14.9,23.8 C15.4,24.1 15.8,24.4 16.3,24.8 C16.8,25.2 17.2,25.6 17.5,26.1 C17.9,26.6 18.2,27.1 18.4,27.8 C18.6,28.4 18.7,29.1 18.7,29.9 C18.6,31.1 18.4,32.2 17.9,33.1 C17.5,34 16.8,34.7 16.1,35.2 C15.4,35.7 14.5,36 13.6,36.1 C12.7,36.2 11.7,36.2 10.8,35.9 C10.3,35.8 9.9,35.6 9.5,35.5 C9.1,35.3 8.7,35.1 8.3,34.9 C8,34.7 7.6,34.5 7.4,34.3 C7.1,34.1 6.9,33.9 6.7,33.6 L7.8,30 C8,30.2 8.2,30.3 8.5,30.5 C8.8,30.7 9.1,30.9 9.4,31 C9.7,31.2 10.1,31.3 10.4,31.5 C10.8,31.6 11.1,31.7 11.5,31.8 L12.3,31.8 C12.5,31.7 12.8,31.6 12.9,31.5 C13.1,31.4 13.2,31.2 13.3,31 C13.4,30.8 13.4,30.6 13.5,30.3 C13.5,30.1 13.5,29.8 13.4,29.6 C13.3,29.4 13.2,29.2 13.1,28.9 C13,28.7 12.8,28.5 12.5,28.2 C12.3,28 12,27.7 11.6,27.5 C11.2,27.2 10.8,26.9 10.4,26.5 C10.1,26.1 9.7,25.8 9.5,25.3 C9.3,24.9 9.1,24.4 8.9,23.9 C8.8,23.4 8.7,22.9 8.7,22.3 C8.7,21.3 8.9,20.5 9.3,19.7 C9.6,18.9 10.1,18.2 10.7,17.5 C11.3,16.9 12,16.3 12.9,15.9 C13.8,15.5 14.7,15.2 15.8,15 C16.3,14.9 16.8,14.9 17.2,14.9 C17.7,14.9 18.1,14.9 18.5,15 C18.9,15.1 19.3,15.1 19.6,15.2 C19.9,15.3 20.2,15.4 20.5,15.5 L18.9,20.3 Z M21.5,7.2 L21.5,6.7 C21.5,5.4 21.3,4.3 21,3.5 C21.3,3.5 21.6,3.6 21.9,3.8 C22.7,4.3 23.2,5.4 23.6,6.6 L21.5,7.2 Z"/>
910        <path fill="currentColor" d="M45.3,29.6 C46.2,30.1 47.8,30.7 49.4,30.7 C50.8,30.7 51.6,29.9 51.6,29 C51.6,28.1 51.1,27.5 49.5,26.6 C47.6,25.5 46.2,24 46.2,22 C46.2,18.5 49.2,16 53.6,16 C55.5,16 57,16.4 57.8,16.8 L56.6,20.3 C55.9,20 54.8,19.6 53.5,19.6 C52.1,19.6 51.2,20.2 51.2,21.3 C51.2,22.1 51.9,22.7 53.1,23.3 C55.1,24.4 56.7,25.9 56.7,28 C56.7,32 53.5,34.2 49,34.1 C46.9,34.1 45,33.5 44.1,32.9 L45.3,29.6 Z M57.7,34.1 L62.6,8.9 L67.6,8.9 L65.7,18.7 L65.8,18.7 C67.1,17.1 68.9,16 71.1,16 C73.7,16 75.2,17.7 75.2,20.5 C75.2,21.4 75.1,22.7 74.8,23.8 L72.8,34.1 L67.8,34.1 L69.7,24.2 C69.8,23.5 69.9,22.7 69.9,22 C69.9,20.9 69.5,20.2 68.3,20.2 C66.7,20.2 65,22.2 64.3,25.5 L62.6,34.2 L57.7,34.2 L57.7,34.1 Z M93.3,23 C93.3,29.1 89.3,34.4 83.4,34.4 C78.9,34.4 76.5,31.3 76.5,27.5 C76.5,21.5 80.5,16.1 86.5,16.1 C91.2,16.1 93.3,19.4 93.3,23 Z M81.6,27.3 C81.6,29.1 82.3,30.5 84,30.5 C86.7,30.5 88.1,25.8 88.1,22.8 C88.1,21.3 87.5,19.8 85.7,19.8 C83.1,19.9 81.6,24.5 81.6,27.3 Z M92.1,41.1 L95.6,23 C96,21 96.4,18.3 96.6,16.4 L101,16.4 L100.7,19.2 L100.8,19.2 C102.1,17.3 104.1,16.2 106.1,16.2 C109.8,16.2 111.3,19.1 111.3,22.5 C111.3,28.5 107.4,34.6 101.6,34.6 C100.4,34.6 99.2,34.1 98.7,34.1 L98.6,34.1 L97.2,41.1 L92.1,41.1 Z M99.3,29.9 C99.8,30.3 100.5,30.6 101.4,30.6 C104.2,30.6 106.1,26 106.1,22.8 C106.1,21.5 105.6,20.1 104.1,20.1 C102.4,20.1 100.7,22.1 100.1,25.2 L99.3,29.9 Z M111.5,34.1 L114.9,16.4 L120,16.4 L116.6,34.1 L111.5,34.1 Z M118,14.5 C116.6,14.5 115.6,13.4 115.6,11.9 C115.6,10.3 116.9,9 118.5,9 C120,9 121,10.1 121,11.6 C121,13.4 119.6,14.5 118,14.5 Z M120.9,34.1 L123.6,20.1 L121.3,20.1 L122,16.4 L124.3,16.4 L124.4,15.6 C124.8,13.5 125.6,11.4 127.3,10 C128.6,8.9 130.4,8.4 132.2,8.4 C133.4,8.4 134.3,8.6 134.9,8.8 L133.9,12.7 C133.5,12.6 133,12.4 132.3,12.4 C130.6,12.4 129.6,13.9 129.3,15.6 L129.1,16.4 L132.6,16.4 L131.9,20.1 L128.4,20.1 L125.7,34.1 L120.9,34.1 L120.9,34.1 Z M138.9,16.4 L139.7,24.3 C139.9,26.1 140.1,27.6 140.1,28.5 L140.2,28.5 C140.6,27.6 141,26.2 141.7,24.3 L144.8,16.4 L150,16.4 L143.9,29.5 C141.7,34 139.6,37.2 137.3,39.4 C135.5,41.1 133.4,41.9 132.4,42.1 L131,37.9 
910C131.8,37.6 132.9,37.2 133.8,36.5 C135,35.7 135.9,34.6 136.5,33.5 C136.6,33.2 136.7,33 136.6,31.6 L133.6,16.4 L138.9,16.4 Z"/>
911      </svg>
912    </a>
913  </small>
914  <small class="password__footer-login password__footer-text">Bist du der Shop-Inhaber? <a href="/admin" class="link underlined-link">Hier einloggen</a></small>
915</div>
916
917
918</div>
919    </footer>
920    <ul hidden>
921      <li id="a11y-new-window-message">Wird in einem neuen Fenster geöffnet.</li>
922    </ul>
923  <style> .green {background: #00ba0b;} div.center-pulse {display: flex; align-items: center;} .circle {display: inline; width: 8px; height: 8px; border-radius: 50%; box-shadow: 0px 0px 1px 1px #0000001a; margin: 0 8px 0 0;} .pulse {animation: pulse-animation 1.5s infinite;} @keyframes pulse-animation {0% {box-shadow: 0 0 0 0px lightgreen; } 100% {box-shadow: 0 0 0 8px rgba(0, 0, 0, 0); }} .mnlc-item-avalilable {font-size: 12px;}  /* Vetrauenselemente - Start */.sales-points {list-style: none; font-size: 12px; font-weight: 250; color: green;} .sales-points svg {min-width: 25px; text-align: left;} ul.sales-points {padding-inline-start: 0px;} .sales-points span,.sales-points svg {display: flex; align-items: center;} .sales-points li {padding: 16px; border-top: 1px solid #dcdcdc; border-right: 1px solid #dcdcdc; border-left: 1px solid #dcdcdc;} .sales-points li:last-child {border-bottom: 1px solid #dcdcdc;} .sales-points .icon {width: 25px; height: 25px; margin-right: 24px;} .product-form__buttons {max-width: 100% !important;}  /* Vetrauenselemente - Ende */button.product-form__submit.button--primary.button--full-width,button[name="checkout"].button--primary,button[name="checkout"].cart__checkout-button,button.product-form__submit.button--primary.button--full-width:hover,button[name="checkout"].button--primary:hover,button[name="checkout"].cart__checkout-button:hover {background-color: #f09500; color: #fff; border: none; outline: none; box-shadow: none;} </style>
924<div id="shopify-block-AV1c1MGppS3Bld2V0Z__1967102994182284862" class="shopify-block shopify-app-block"><!-- BEGIN app snippet: connected_sdk_script -->
924<script src='https://www.paypalobjects.com/pa/js/min/pa.js'></script>
924
925
926<script
927  src='https://www.paypal.com/sdk/js?client-id=AbtXlp5R3xc83T9xW_ZXKTK8IVZ-14EMelDioU4VC285IqSuxUI4yotKxjV0sz_X6YsONYi10vSBPNKM&merchant-id=DMA4TKM2QXZ5U&components=messages'
928  data-namespace='PayPalSDK'
929  data-partner-attribution-id='JADEDPIXEL_SHOPPINGCART_EC_CA'
930></script>
930
931<!-- END app snippet --><!-- BEGIN app snippet: utils -->
931<script>
932  // ============================================
933  // Core Utilities
934  // ============================================
935
936  // Setup FPTI Analytics
937  if (PAYPAL && PAYPAL.analytics) {
938    PAYPAL.analytics.setup({
939      data: {
940        pgrp: 'shopify:messaging:app-embed',
941        comp: 'shopify-app-embed',
942      },
943    });
944  }
945
946  const recordEvent = (event_name, additionalData) => {
947    PAYPAL.analytics.instance.recordEvent(event_name, {
948      theme: window?.Shopify?.theme?.name || 'unknown',
949      shop: window?.Shopify?.shop || 'unknown',
950      path: window.location.pathname,
951      flow: 'Shopify - Pay Later',
952      space_key: 'SKD8GM',
953      ...additionalData,
954    });
955  };
956
957  // In Theme Editor when using Advanced Settings
958  // User chooses copy as JS Path from their browser
959  // The pasted value will be a string that contains "document.querySelector("...")
960  // Remove document.querySelector(" and ")
961  // Using JS Path we can ensure the path to the element is accurate
962  const parseSelector = (selector) => {
963    try {
964      // Handle both single and double quotes
965      return selector
966        .replace(/document\.querySelector\(["']/g, '')
967        .replace(/["']\)/g, '');
968    } catch (e) {
969      recordEvent('appEmbed:parseSelector:error', { error: e.message });
970    }
971  };
972
973  // Waits for Element to be rendered
974  // Uses mutation observer to watch for changes in the DOM
975  // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
976  // On changes, check for the selector again
977  const waitForElement = (selector) => {
978    try {
979      return new Promise((resolve) => {
980        const existing = document.querySelector(selector);
981        if (existing) return resolve(existing);
982
983        const observer = new MutationObserver(() => {
984          const el = document.querySelector(selector);
985          if (el) {
986            observer.disconnect();
987            resolve(el);
988          }
989        });
990
991        observer.observe(document.body, {
992          childList: true,
993          subtree: true,
994        });
995      });
996    } catch (e) {
997      recordEvent('appEmbed:waitForElement:error', { error: e.message });
998    }
999  };
1000
1001  // Formats correct cart/drawer subtotal and adds or updates messaging
1002  const addOrUpdateMessagingPriceAttribute = async (price, locator, messaging) => {
1003    try {
1004      // Format price to 2 decimal places ex: 150000 => 1500.00
1005      // Messaging requires price to be in string format
1006      const formattedPrice = Number((price / 100).toFixed(2)).toString();
1007
1008      const messagingId = messaging.id;
1009      const existingMessaging = document.getElementById(messagingId);
1010
1011      if (existingMessaging) {
1012        // Update the data-pp-amount attribute on the existing element
1013        existingMessaging.setAttribute('data-pp-amount', formattedPrice);
1014      } else {
1015        const element = await waitForElement(locator);
1016
1017        const updatedPriceMessaging = messaging.cloneNode();
1018        updatedPriceMessaging.setAttribute('data-pp-amount', formattedPrice);
1019
1020        element.after(updatedPriceMessaging);
1021      }
1022    } catch (e) {
1023      recordEvent('appEmbed:addOrUpdateMessagingPriceAttribute:error', { error: e.message });
1024    }
1025  };
1026
1027  // Fetches cart details from Shopify cart endpoint
1028  const fetchCartDetails = async () => {
1029    try {
1030      const response = await fetch('/cart.js');
1031      const cart = await response.json();
1032
1033      return cart.total_price;
1034    } catch (e) {
1035      recordEvent('appEmbed:fetchCartDetails:error', { error: e.message });
1036    }
1037  };
1038
1039  // Fetches variant details Shopify product endpoint
1040  // https://shopify.dev/docs/api/ajax/reference/product
1041  const fetchVariant = async () => {
1042    try {
1043      // Ex: https://test-store.myshopify.com/products/the-multi-location-snowboard?variant=45268551368883
1044      const urlParams = new URLSearchParams(window.location.search);
1045      const urlVariantId = parseInt(urlParams.get('variant'), 10);
1046      const productHandle = window.location.pathname.split('/products/')[1]?.split('?')[0];
1047
1048      const response = await fetch(`/products/${productHandle}.js`);
1049      const productData = await response.json();
1050      const variants = productData.variants;
1051      const selectedVariant = variants.find(v => v.id === urlVariantId);
1052
1053      if (selectedVariant) {
1054        return selectedVariant;
1055      }
1056
1057      return variants.find(v => v.available) || variants[0];
1058    } catch (e) {
1059      recordEvent('appEmbed:fetchVariant:error', { error: e.message });
1060    }
1061  };
1062
1063  // Get the selected variant ID from URL, form input, or select element
1064  const getSelectedVariantId = () => {
1065    try {
1066      const urlParams = new URLSearchParams(window.location.search);
1067      const urlVariant = urlParams.get('variant');
1068      if (urlVariant) return parseInt(urlVariant, 10);
1069
1070      const formInput = document.querySelector('form[action*="/cart/add"] input[name="id"]');
1071      if (formInput?.value) return parseInt(formInput.value, 10);
1072
1073      const selectInput = document.querySelector('form[action*="/cart/add"] select[name="id"]');
1074      if (selectInput?.value) return parseInt(selectInput.value, 10);
1075
1076      return null;
1077    } catch (e) {
1078      recordEvent('appEmbed:getSelectedVariantId:error', { error: e.message });
1079      return null;
1080    }
1081  };
1082
1083  const getShopifyData = () => {
1084    try {
1085      const selectedVariantId = getSelectedVariantId();
1086
1087      const findVariant = (variants) => {
1088        if (!variants?.length) return null;
1089        if (selectedVariantId) {
1090          const selected = variants.find(v => v.id === selectedVariantId);
1091          if (selected) return selected;
1092        }
1093        return variants.find(v => v.available) || variants[0];
1094      };
1095
1096      if (window.meta?.product) {
1097        const product = window.meta.product;
1098        const variant = findVariant(product.variants);
1099        return {
1100          product: { title: product.title, vendor: product.vendor, type: product.type, id: product.id },
1101          price: variant ? {
1102            priceInCents: variant.price,
1103            compareAtPrice: variant.compare_at_price,
1104            currency: window.Shopify?.currency?.active || 'USD',
1105            variantId: variant.id,
1106            variantTitle: variant.title
1107          } : null
1108        };
1109      }
1110
1111      if (window.ShopifyAnalytics?.meta?.product) {
1112        const product = window.ShopifyAnalytics.meta.product;
1113        const variant = findVariant(product.variants);
1114        return {
1115          product: { title: product.title, vendor: product.vendor, id: product.id },
1116          price: variant ? {
1117            priceInCents: variant.price,
1118            currency: window.Shopify?.currency?.active || 'USD',
1119            variantId: variant.id
1120          } : null
1121        };
1122      }
1123
1124      return null;
1125    } catch (e) {
1126      recordEvent('appEmbed:getShopifyData:error', { error: e.message });
1127      return null;
1128    }
1129  };
1130
1131  // Generic function to watch for changes in the DOM
1132  // and listen for specific API calls made by the Shopify store
1133  // Callback provides specific logic for handling the response
1134  const watchForChanges = (locator, messaging, callback) => {
1135    try {
1136      // Overrides the native `fetch` function to listen for specific API calls.
1137      // Wrapped in an Immediately Invoked Function Expression (IIFE)
1138      // To avoid polluting the global namespace.
1139      (function (window, windowFetch) {
1140        // Check if `fetch` is a function. If not, exit early.
1141        if (typeof fetch !== 'function') return;
1142
1143        window.fetch = function () {
1144          // Call the original `fetch` function with the provided arguments.
1145          const response = windowFetch.apply(this, arguments);
1146
1147          response.then(async (res) => {
1148            if (typeof callback === 'function') {
1149              callback(res, locator, messaging);
1150            }
1151          });
1152
1153          // Return the original `fetch` response.
1154          return response;
1155        };
1156      })(window, window.fetch);
1157    } catch (e) {
1158      recordEvent('appEmbed:watchForChanges:error', { error: e.message });
1159    }
1160  };
1161
1162  // Provides ability to watch for cart changes
1163  // such as increment, decrement, or remove items
1164  // Also handles adding new items which opens Cart Drawer
1165  // and updates the messaging with the new cart total
1166  // This function is used for both Cart Drawer and Cart Page
1167  const watchForCartChanges = (locator, messaging) => {
1168    const cartChangeCallback = async (res, locator, messaging) => {
1169      // Determine the id of messaging div either #paypal-upstream-messaging-cart-{page | drawer}
1170      const messagingId = messaging.id;
1171
1172      // Changes (e.g., increment, decrement, or remove items).
1173      if (res.url.includes('/cart/change')) {
1174        // Clone the response to read its JSON data without consuming the original response.
1175        res
1176          .clone()
1177          .json()
1178          .then((data) => {
1179            addOrUpdateMessagingPriceAttribute(data.total_price, locator, messaging);
1180          });
1181
1182        // Called when adding a new item which opens Cart Drawer
1183      } else if (res.url.includes('/cart/add')) {
1184        // Adding items does not return the updated cart details,
1185        // Fetch the updated cart details (e.g., total_price).
1186        const updatedPrice = await fetchCartDetails();
1187
1188        // Introduce a delay to handle potential race conditions where the cart drawer has not rendered yet.
1189        setTimeout(async () => {
1190          await addOrUpdateMessagingPriceAttribute(updatedPrice, locator, messaging);
1191        }, 500);
1192      }
1193    };
1194
1195    watchForChanges(locator, messaging, cartChangeCallback);
1196  };
1197
1198  // Provides ability to watch for product specific changes
1199  // such as variant selection on product pages
1200  const watchForProductChanges = (locator, messaging) => {
1201    let lastVariantId = new URLSearchParams(window.location.search).get('variant');
1202
1203    const handleVariantChange = async () => {
1204      const currentVariantId = new URLSearchParams(window.location.search).get('variant');
1205      if (currentVariantId && currentVariantId !== lastVariantId) {
1206        lastVariantId = currentVariantId;
1207
1208        const newVariantData = await fetchVariant();
1209        const newPriceInCents = newVariantData?.price;
1210
1211        if (newPriceInCents) {
1212          await addOrUpdateMessagingPriceAttribute(newPriceInCents, locator, messaging);
1213        } else {
1214          recordEvent('appEmbed:watchForProductChanges:error:noNewVariantPrice');
1215        }
1216      }
1217    };
1218
1219    // Shopify themes can either handle variant changes on the client-side or server-side (via variant API calls)
1220    // We will "intercept" and handle variant changes by:
1221    // 1. Watching for URL changes
1222    const _pushState = history.pushState.bind(history);
1223    const _replaceState = history.replaceState.bind(history);
1224
1225    history.pushState = function (...args) {
1226      _pushState(...args);
1227      handleVariantChange();
1228    };
1229
1230    history.replaceState = function (...args) {
1231      _replaceState(...args);
1232      handleVariantChange();
1233    };
1234
1235    // 2. Watching for back/forward browser clicks
1236    window.addEventListener('popstate', handleVariantChange);
1237
1238    // 3. Fallback: Watching for variant API calls
1239    // Future optimization: This fallback could be removed if all Shopify themes can be handled with 1. and 2.
1240    const productChangeCallback = async (res, locator, messaging) => {
1241      if (res.url.includes('/variants')) {
1242        await handleVariantChange();
1243        return;
1244      }
1245    };
1246
1247    watchForChanges(locator, messaging, productChangeCallback);
1248  };  
1249</script>
1249
1250<!-- END app snippet --><!-- BEGIN app snippet: price-detection -->
1250<script>
1251  // ============================================
1252  // Price Detection & Element Scoring
1253  // Depends on: utils.liquid (recordEvent, getShopifyData)
1254  // ============================================
1255
1256  const extractPriceFromText = (text) => {
1257    const match = text.match(/[\d,]+\.?\d*/);
1258    if (!match) return null;
1259    return parseFloat(match[0].replace(/,/g, ''));
1260  };
1261
1262  const textMatchesPrice = (text, knownPriceInCents) => {
1263    const extracted = extractPriceFromText(text);
1264    if (extracted === null) return false;
1265    const knownPrice = knownPriceInCents / 100;
1266    return Math.abs(extracted - knownPrice) < 0.01;
1267  };
1268
1269  const hasStrikethrough = (element) => {
1270    let el = element;
1271    while (el && el !== document.body) {
1272      const style = getComputedStyle(el);
1273      if (style.textDecoration.includes('line-through') ||
1274          style.textDecorationLine?.includes('line-through')) {
1275        return true;
1276      }
1277      if (['S', 'DEL', 'STRIKE'].includes(el.tagName)) {
1278        return true;
1279      }
1280      el = el.parentElement;
1281    }
1282    return false;
1283  };
1284
1285  // Find the add-to-cart button. Result is cached since the button doesn't change per page load.
1286  let _cachedAddToCartButton;
1287  const findAddToCartButton = () => {
1288    if (_cachedAddToCartButton !== undefined) return _cachedAddToCartButton;
1289    try {
1290      const formButton = document.querySelector('form[action*="/cart/add"] button[type="submit"]');
1291      if (formButton) return (_cachedAddToCartButton = formButton);
1292
1293      const buttons = document.querySelectorAll('button');
1294      for (const btn of buttons) {
1295        const text = btn.textContent.toLowerCase();
1296        if (text.includes('add to cart') || text.includes('add to bag') ||
1297            text.includes('buy now') || text.includes('add to basket')) {
1298          return (_cachedAddToCartButton = btn);
1299        }
1300      }
1301
1302      return (_cachedAddToCartButton = null);
1303    } catch (e) {
1304      recordEvent('appEmbed:findAddToCartButton:error', { error: e.message });
1305      return (_cachedAddToCartButton = null);
1306    }
1307  };
1308
1309  // Find element containing specific text (used for product title proximity).
1310  // Result is cached per text string — title is static per page load and scoreElement
1311  // calls this once per candidate, so without caching it's O(candidates) full DOM walks.
1312  let _titleElementCache = {};
1313  const findElementContainingText = (text) => {
1314    if (text in _titleElementCache) return _titleElementCache[text];
1315    try {
1316      const normalizedText = text.toLowerCase().trim();
1317      const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
1318
1319      let node;
1320      while (node = walker.nextNode()) {
1321        const nodeText = node.textContent.trim().toLowerCase();
1322        if (nodeText.length > 5 && normalizedText.includes(nodeText.substring(0, 20))) {
1323          const el = node.parentElement;
1324          const rect = el.getBoundingClientRect();
1325          if (rect.width > 0 && rect.height > 0) {
1326            const fontSize = parseFloat(getComputedStyle(el).fontSize);
1327            if (fontSize >= 16) return (_titleElementCache[text] = el);
1328          }
1329        }
1330      }
1331      return (_titleElementCache[text] = null);
1332    } catch (e) {
1333      return null;
1334    }
1335  };
1336
1337  const getViewportThresholds = () => {
1338    const vh = window.innerHeight;
1339    const isMobile = window.innerWidth < 768;
1340
1341    return {
1342      position: [[vh * 0.6, 50], [vh * 1.2, 30], [vh * 2.0, 10]],
1343      fontSize: [
1344        [isMobile ? 18 : 24, 40],
1345        [isMobile ? 14 : 18, 25],
1346        [isMobile ? 12 : 14, 10],
1347      ],
1348      proximity: {
1349        close:  isMobile ? 60  : 100,
1350        medium: isMobile ? 120 : 200,
1351        far:    isMobile ? 240 : 400,
1352      },
1353    };
1354  };
1355
1356  const getTieredScore = (value, tiers, defaultScore = 0) => {
1357    for (const [threshold, points] of tiers) {
1358      if (value < threshold) return points;
1359    }
1360    return defaultScore;
1361  };
1362
1363  // Scores a DOM element on how likely it is to be the product's main price.
1364  // Higher score = better candidate. Factors:
1365  //   - Position on page (elements higher up score better)
1366  //   - Font size (larger text = more likely a displayed price)
1367  //   - Proximity to product title and add-to-cart button
1368  //   - Structural exclusions (footer/header/nav/hidden = heavy penalty)
1369  //   - Strikethrough detection (compare-at prices = heavy penalty)
1370  const scoreElement = (element, productMeta = null, debug = false) => {
1371    let score = 0;
1372    const breakdown = debug ? {} : null;
1373    const { position, fontSize, proximity } = getViewportThresholds();
1374    const { close, medium, far } = proximity;
1375    const rect = element.getBoundingClientRect();
1376
1377    // POSITION ON PAGE
1378    const absoluteTop = rect.top + window.scrollY;
1379    const posScore = getTieredScore(absoluteTop, position, -30);
1380    score += posScore;
1381    if (debug) breakdown.position = `${posScore >= 0 ? '+' : ''}${posScore} (top ${Math.round(absoluteTop)}px)`;
1382
1383    // FONT SIZE
1384    const fontPx = parseFloat(getComputedStyle(element).fontSize);
1385    const fontScore = fontSize.find(([t]) => fontPx >= t)?.[1] ?? -10;
1386    score += fontScore;
1387    if (debug) breakdown.fontSize = `${fontScore >= 0 ? '+' : ''}${fontScore} (${fontPx}px)`;
1388
1389    // PROXIMITY TO PRODUCT TITLE
1390    if (productMeta?.title) {
1391      const titleElement = findElementContainingText(productMeta.title);
1392      if (titleElement) {
1393        const distance = Math.abs(titleElement.getBoundingClientRect().bottom - rect.top);
1394        const titleScore = getTieredScore(distance, [[close, 40], [medium, 25], [far, 10]], 0);
1395        score += titleScore;
1396        if (debug) breakdown.titleProximity = `+${titleScore} (${Math.round(distance)}px)`;
1397      } else if (debug) {
1398        breakdown.titleProximity = 'title element not found';
1399      }
1400    } else if (debug) {
1401      breakdown.titleProximity = 'no product title';
1402    }
1403
1404    // PROXIMITY TO ADD-TO-CART BUTTON
1405    const addButton = findAddToCartButton();
1406    if (addButton) {
1407      const distance = Math.abs(addButton.getBoundingClientRect().top - rect.top);
1408      const cartScore = getTieredScore(distance, [[close, 30], [medium, 20], [far, 10]], 0);
1409      score += cartScore;
1410      if (debug) breakdown.cartProximity = `+${cartScore} (${Math.round(distance)}px)`;
1411    } else if (debug) {
1412      breakdown.cartProximity = 'add-to-cart not found';
1413    }
1414
1415    // STRUCTURAL EXCLUSIONS
1416    const exclusions = [
1417      ['footer, header, nav', 'in footer/header/nav'],
1418      ['button, a[href*="/cart"], [type="submit"]', 'in button/link'],
1419      ['[aria-hidden="true"], [hidden], .hidden, .visually-hidden', 'hidden'],
1420    ];
1421    for (const [selector, reason] of exclusions) {
1422      if (element.closest(selector)) {
1423        score -= 100;
1424        if (debug) breakdown.structural = `-100 (${reason})`;
1425        break;
1426      }
1427    }
1428    if (debug && !breakdown.structural) breakdown.structural = '+0';
1429
1430    // STRIKETHROUGH
1431    if (hasStrikethrough(element)) {
1432      score -= 100;
1433      if (debug) breakdown.strikethrough = '-100 (compare-at price)';
1434    } else if (debug) {
1435      breakdown.strikethrough = '+0';
1436    }
1437
1438    if (debug) {
1439      breakdown.totalScore = score;
1440      breakdown.elementText = element.textContent.trim().substring(0, 30);
1441      breakdown.elementTag = element.tagName;
1442    }
1443
1444    return debug ? { score, breakdown } : score;
1445  };
1446
1447  // Find all elements containing a specific price value
1448  const findElementsWithPrice = (knownPriceInCents, productMeta = null, debug = false, log = () => {}) => {
1449    const candidates = [];
1450    const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
1451
1452    let node;
1453    while (node = walker.nextNode()) {
1454      const text = node.textContent.trim();
1455      if (text.length > 30 || !textMatchesPrice(text, knownPriceInCents)) continue;
1456
1457      const element = node.parentElement;
1458      const rect = element.getBoundingClientRect();
1459
1460      if (rect.width === 0 || rect.height === 0 || hasStrikethrough(element)) continue;
1461
1462      const score = scoreElement(element, productMeta, false);
1463      candidates.push({ element, text, score });
1464    }
1465
1466    if (debug && candidates.length > 0) {
1467      candidates.sort((a, b) => b.score - a.score);
1468      log(`  Candidates: ${candidates.length}, top: score=${candidates[0].score}, text="${candidates[0].text}"`);
1469    }
1470
1471    return candidates;
1472  };
1473
1474  // Find the /cart/add form by traversing from the price element
1475  // This is more reliable than name-based container detection since all Shopify themes have this form
1476  const findCartFormFromPrice = (priceElement, debug = false, log = () => {}) => {
1477    let el = priceElement;
1478
1479    while (el && el !== document.body) {
1480      if (el.tagName === 'FORM' && el.action?.includes('/cart/add')) {
1481        if (debug) log(`  Found /cart/add form (element itself)`);
1482        return el;
1483      }
1484
1485      let sibling = el.nextElementSibling;
1486      while (sibling) {
1487        if (sibling.tagName === 'FORM' && sibling.action?.includes('/cart/add')) {
1488          if (debug) log(`  Found /cart/add form as sibling`);
1489          return sibling;
1490        }
1491        // Check if sibling contains the form
1492        const formInSibling = sibling.querySelector('form[action*="/cart/add"]');
1493        if (formInSibling) {
1494          if (debug) log(`  Found /cart/add form inside sibling`);
1495          return formInSibling;
1496        }
1497        sibling = sibling.nextElementSibling;
1498      }
1499
1500      el = el.parentElement;
1501    }
1502
1503    if (debug) log(`  No /cart/add form found`);
1504    return null;
1505  };
1506
1507  // Fallback: walk up from the price text element to find a suitable wrapper.
1508  // Used when no /cart/add form exists near the price element.
1509  const findPriceContainer = (priceElement) => {
1510    let el = priceElement;
1511    let bestContainer = priceElement;
1512
1513    while (el && el !== document.body) {
1514      // Look for elements with price-related IDs (common Shopify pattern)
1515      if (el.id && /price/i.test(el.id)) {
1516        bestContainer = el;
1517      }
1518      // Look for elements with price-related classes that seem like containers
1519      if (el.className && typeof el.className === 'string') {
1520        const classes = el.className.toLowerCase();
1521        if (/\bprice\b/.test(classes) && !/price-item|price__regular|price__sale/.test(classes)) {
1522          bestContainer = el;
1523        }
1524      }
1525      // Stop at major structural elements
1526      if (el.tagName === 'SECTION' || el.tagName === 'ARTICLE' || el.tagName === 'MAIN') {
1527        break;
1528      }
1529      el = el.parentElement;
1530    }
1531
1532    return bestContainer;
1533  };
1534
1535  // Try common Shopify theme price selectors (Dawn and derivatives)
1536  const findPriceByTemplateSelector = (debug = false, log = () => {}) => {
1537    const selectors = [
1538      '[id*="price-template"]',  // Dawn theme pattern
1539      '.price-item--regular:not(s):not(del)',
1540      '[data-product-price]',
1541    ];
1542
1543    for (const selector of selectors) {
1544      const el = document.querySelector(selector);
1545      if (el && !hasStrikethrough(el)) {
1546        if (debug) log(`Template selector found: ${selector}`);
1547        return el;
1548      }
1549    }
1550    return null;
1551  };
1552
1553  // Check if we're in an isolated/sandboxed iframe (theme editor)
1554  const isIsolatedContext = () => {
1555    if (window === window.top) return false; // Not in iframe
1556    try {
1557      // Try to access parent - if cross-origin, we're isolated
1558      const test = window.parent.document;
1559      return false; // Can access parent, not isolated
1560    } catch (e) {
1561      return true; // Cross-origin, we're isolated
1562    }
1563  };
1564
1565  // Try to find price element in sibling iframes (theme editor workaround)
1566  const findPriceInSiblingIframes = (knownPriceInCents) => {
1567    const iframes = document.querySelectorAll('iframe');
1568
1569    for (const iframe of iframes) {
1570      try {
1571        const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
1572        if (!iframeDoc) continue;
1573
1574        const priceElement = iframeDoc.querySelector('.price-item, .price, [data-product-price]');
1575        if (priceElement) {
1576          return { element: priceElement, document: iframeDoc };
1577        }
1578      } catch (e) {
1579        // Cross-origin iframe, skip
1580      }
1581    }
1582
1583    return null;
1584  };
1585
1586  // Helper: Insert messaging near a price element (before cart form or after price container).
1587  // Returns the price container element used as the logical anchor.
1588  const insertMessagingNearPrice = (priceElement, messaging, debug = false, log = () => {}) => {
1589    const cartForm = findCartFormFromPrice(priceElement, debug, log);
1590    const container = findPriceContainer(priceElement);
1591    if (cartForm) {
1592      cartForm.before(messaging.cloneNode());
1593      if (debug) log('Inserted messaging before /cart/add form');
1594    } else {
1595      container.after(messaging.cloneNode());
1596      if (debug) log('Inserted after price container (no form found)');
1597    }
1598    return container;
1599  };
1600
1601  // Insert messaging after price element
1602  const insertMessagingWithRetry = (shopifyData, messaging, debug = false, log = () => {}) => {
1603    // Skip visual preview iframe
1604    if (window.location.search.includes('source=visualPreviewInitialLoad')) return;
1605    if (document.querySelector('#paypal-upstream-messaging-product')) return;
1606
1607    const liquidPriceInCents = shopifyData?.price?.priceInCents;
1608    const isIsolated = isIsolatedContext();
1609
1610    if (debug) {
1611      log('=== Price Detection ===');
1612      log(`Context: ${isIsolated ? 'Theme Editor' : 'Live Storefront'}`);
1613      log(`Price: ${liquidPriceInCents} cents ($${(liquidPriceInCents / 100).toFixed(2)})`);
1614    }
1615
1616    // Priority 1: Template selectors (common theme patterns like Dawn)
1617    const templateElement = findPriceByTemplateSelector(debug, log);
1618    if (templateElement) {
1619      return insertMessagingNearPrice(templateElement, messaging, debug, log);
1620    }
1621
1622    // Priority 2: Scoring-based price detection
1623    const priceElement = findPriceElement(shopifyData, debug, log);
1624    if (priceElement) {
1625      return insertMessagingNearPrice(priceElement, messaging, debug, log);
1626    }
1627
1628    // Priority 3: Sibling iframes (theme editor only)
1629    if (isIsolated) {
1630      const siblingResult = findPriceInSiblingIframes(liquidPriceInCents);
1631      if (siblingResult) {
1632        return insertMessagingNearPrice(siblingResult.element, messaging, debug, log);
1633      }
1634    }
1635
1636    if (!isIsolated) {
1637      log('Could not find price element. Consider using Advanced Settings with a custom selector.');
1638    }
1639    return null;
1640  };
1641
1642  const findPriceElement = (shopifyData = null, debug = false, log = () => {}) => {
1643    try {
1644      const knownPriceInCents = shopifyData?.price?.priceInCents;
1645      const productMeta = shopifyData?.product;
1646
1647      if (debug) log(`findPriceElement: ${knownPriceInCents} cents`);
1648
1649      if (knownPriceInCents) {
1650        const candidates = findElementsWithPrice(knownPriceInCents, productMeta, debug, log);
1651        if (candidates.length > 0) {
1652          candidates.sort((a, b) => b.score - a.score);
1653          if (debug) log(`  → FOUND (score=${candidates[0].score})`);
1654          return candidates[0].element;
1655        }
1656      }
1657
1658      if (debug) log('  → null (no candidates)');
1659      return null;
1660    } catch (e) {
1661      if (debug) log(`  → Error: ${e.message}`);
1662      recordEvent('appEmbed:findPriceElement:error', { error: e.message });
1663      return null;
1664    }
1665  };
1666</script>
1666
1667<!-- END app snippet --><!-- BEGIN app snippet: navigator-panel --><template id="pp-nav-template">
1668  <style>
1669    /* --- Floating placement panel shell --- */
1670    #pp-nav-panel {
1671      position: fixed;
1672      top: 50%;
1673      left: 20px;
1674      transform: translateY(-50%);
1675      background: #fff;
1676      border-radius: 12px;
1677      font-family: system-ui, -apple-system, sans-serif;
1678      font-size: 13px;
1679      z-index: 999999;
1680      width: 340px;
1681      box-shadow: 0 8px 32px rgba(0,0,0,0.18);
1682      overflow: hidden;
1683      transition: transform 0.3s ease, height 0.3s ease;
1684    }
1685    #pp-nav-panel.minimized {
1686      display: none;
1687    }
1688
1689    /* --- Minimized pill button --- */
1690    #pp-nav-pill {
1691      position: fixed;
1692      bottom: 20px;
1693      left: 20px;
1694      background: #003087;
1695      color: #fff;
1696      border: none;
1697      border-radius: 24px;
1698      padding: 10px 18px;
1699      font-family: system-ui, -apple-system, sans-serif;
1700      font-size: 13px;
1701      font-weight: 600;
1702      cursor: pointer;
1703      z-index: 999999;
1704      box-shadow: 0 4px 16px rgba(0,48,135,0.3);
1705      display: none;
1706      align-items: center;
1707      gap: 8px;
1708      transition: box-shadow 0.2s;
1709    }
1710    #pp-nav-pill:hover {
1711      box-shadow: 0 6px 20px rgba(0,48,135,0.45);
1712    }
1713
1714    /* --- Header --- */
1715    .pp-panel-header {
1716      background: #003087;
1717      color: #fff;
1718      padding: 14px 16px;
1719      display: flex;
1720      align-items: center;
1721      justify-content: space-between;
1722    }
1723    .pp-panel-title {
1724      font-size: 14px;
1725      font-weight: 700;
1726      margin: 0;
1727      letter-spacing: 0.01em;
1728    }
1729    .pp-minimize-btn {
1730      background: none;
1731      border: none;
1732      color: rgba(255,255,255,0.8);
1733      cursor: pointer;
1734      font-size: 18px;
1735      line-height: 1;
1736      padding: 2px;
1737      border-radius: 4px;
1738      transition: color 0.15s;
1739    }
1740    .pp-minimize-btn:hover {
1741      color: #fff;
1742    }
1743
1744    /* --- Panel body --- */
1745    .pp-panel-content {
1746      padding: 16px;
1747    }
1748
1749    /* --- Step info boxes --- */
1750    .pp-step-box {
1751      border-radius: 8px;
1752      padding: 10px 12px;
1753      font-size: 12px;
1754      line-height: 1.5;
1755      margin-bottom: 12px;
1756      display: flex;
1757      align-items: flex-start;
1758      gap: 8px;
1759    }
1760    .pp-step-box.blue {
1761      background: #e8f4fd;
1762      border: 1px solid #b8dff5;
1763      color: #0a5a96;
1764    }
1765    .pp-step-box.green {
1766      background: #e6f9ee;
1767      border: 1px solid #a3e4b8;
1768      color: #1a7a3a;
1769    }
1770    .pp-step-text {
1771      flex: 1;
1772    }
1773    .pp-step-text p {
1774      margin: 0 0 8px 0;
1775    }
1776    .pp-step-text p:last-child {
1777      margin-bottom: 0;
1778    }
1779    .pp-step-text strong {
1780      display: block;
1781      font-size: 12px;
1782      margin-bottom: 2px;
1783    }
1784    .pp-step-dismiss {
1785      background: none;
1786      border: none;
1787      color: inherit;
1788      opacity: 0.5;
1789      cursor: pointer;
1790      font-size: 16px;
1791      line-height: 1;
1792      padding: 0;
1793      flex-shrink: 0;
1794    }
1795    .pp-step-dismiss:hover {
1796      opacity: 1;
1797    }
1798
1799    /* --- Warning banners --- */
1800    .pp-warning {
1801      background: #fff3cd;
1802      border: 1px solid #ffc107;
1803      border-radius: 8px;
1804      padding: 10px 12px;
1805      margin-bottom: 12px;
1806      font-size: 12px;
1807      color: #856404;
1808      line-height: 1.4;
1809    }
1810    .pp-warning-icon {
1811      margin-right: 4px;
1812    }
1813
1814    /* --- Pick placement + copy actions --- */
1815    .pp-pick-btn {
1816      width: 100%;
1817      padding: 12px;
1818      border: 2px solid #0070ba;
1819      border-radius: 8px;
1820      background: #0070ba;
1821      color: #fff;
1822      cursor: pointer;
1823      font-size: 13px;
1824      font-weight: 600;
1825      transition: all 0.15s;
1826      display: flex;
1827      align-items: center;
1828      justify-content: center;
1829      gap: 8px;
1830    }
1831    .pp-pick-btn:hover {
1832      opacity: 0.9;
1833    }
1834    .pp-pick-btn.active {
1835      background: #f0f7ff;
1836      color: #0070ba;
1837      border-color: #b8dff5;
1838    }
1839    .pp-pick-btn.active:hover {
1840      background: #e0efff;
1841    }
1842
1843    /* --- Copy button --- */
1844    #pp-apply-btn {
1845      width: 100%;
1846      background: #28a745;
1847      color: #fff;
1848      border: none;
1849      padding: 12px;
1850      border-radius: 8px;
1851      font-weight: 600;
1852      cursor: pointer;
1853      font-size: 13px;
1854      transition: all 0.2s;
1855      display: none;
1856      align-items: center;
1857      justify-content: center;
1858      gap: 8px;
1859      margin-top: 12px;
1860    }
1861    #pp-apply-btn:hover {
1862      opacity: 0.9;
1863    }
1864    #pp-apply-btn.applied {
1865      background: #28a745;
1866    }
1867
1868    /* --- Step 2 confirmation --- */
1869    #pp-step2 {
1870      display: none;
1871      margin-top: 18px;
1872    }
1873  </style>
1874  <div class='pp-panel-header'>
1875    <div class='pp-panel-title'>PayPal Pay Later Messaging</div>
1876    <button class='pp-minimize-btn' id='pp-collapse-btn' title='Minimize panel'>&#x25BE;</button>
1877  </div>
1878  <div class='pp-panel-content'>
1879    <div id='pp-warning' class='pp-warning' style='display: none;'></div>
1880    <div id='pp-inspector-warning' class='pp-warning' style='display: none;'></div>
1881    <div class='pp-step-box blue' id='pp-step1'>
1882      <span class='pp-step-text'
1883        ><strong>Step 1: Choose message placement</strong>
1884        Click the button below and then hover over your page to select a placement.
1885      </span>
1886    </div>
1887    <button id='pp-pick-btn' class='pp-pick-btn'>&#x25CE; Start Picking Placement</button
1888    ><button id='pp-apply-btn'>Copy Current Placement</button>
1889    <div id='pp-step2' style='display:none;'>
1890      <div class='pp-step-box green'>
1891        <span class='pp-step-text'
1892          ><strong>Step 2: Paste and save</strong>
1893          <p style='margin: 0 0 8px 0;'>
1894            You have copied the placement for the <b id='pp-context-name'>Product Page</b>.
1895          </p>
1896          <p style='margin: 0;'>
1897            Go back to the App Embeds section, and in the Paypal Advanced Settings, paste the copied value into the
1898            <b id='pp-selector-name'>Product Page</b> field and click the 'Save' button in the top right corner.
1899          </p></span
1900        ><button class='pp-step-dismiss' id='pp-step2-dismiss' title='Dismiss'>&times;</button>
1901      </div>
1902    </div>
1903  </div>
1904</template>
1905<!-- END app snippet --><!-- BEGIN app snippet: navigator -->
1905<script>
1906  // ============================================
1907  // DOM Traversal Controls for Theme Editor
1908  // Depends on: price-detection.liquid (isIsolatedContext)
1909  // ============================================
1910
1911  const OVERLAY_STYLE =
1912    'position:fixed;pointer-events:none;background:rgba(255,152,0,0.12);border:2px solid rgba(255,152,0,0.6);z-index:999998;display:none;';
1913  const OVERLAY_LABEL_STYLE =
1914    'position:absolute;bottom:100%;left:-2px;background:#f57c00;color:#fff;font:10px system-ui;padding:2px 6px;border-radius:3px 3px 0 0;white-space:nowrap;';
1915  const COPY_BUTTON_LABEL = 'Copy Current Placement';
1916  const COPIED_BUTTON_LABEL = 'Placement Copied!';
1917
1918  const isInOverlay = (el) => {
1919    while (el && el !== document.body) {
1920      if (getComputedStyle(el).position === 'fixed') return true;
1921      el = el.parentElement;
1922    }
1923    return false;
1924  };
1925
1926  // Position a fixed overlay to cover a target element
1927  const positionOverlayOnElement = (overlay, el) => {
1928    const rect = el.getBoundingClientRect();
1929    Object.assign(overlay.style, {
1930      top: rect.top + 'px',
1931      left: rect.left + 'px',
1932      width: rect.width + 'px',
1933      height: rect.height + 'px',
1934      display: 'block',
1935    });
1936  };
1937
1938  // Module-level refs for global listeners added by createNavigationPanel.
1939  // Stored here so they can be removed if the panel is re-initialized.
1940  let _panelInspectorActivate = null;
1941  let _panelInspectorDeactivate = null;
1942  let _highlightedElement = null;
1943  let _panelPickModeCleanup = null;
1944
1945  // Detect UID pattern in ID (Shopify's --suffix or long numeric/hex suffixes)
1946  const hasUid = (id) => {
1947    if (!id) return false;
1948    if (/--/.test(id)) return true;
1949    return /[-_](\d{5,}|[a-f0-9]{8,})$/i.test(id);
1950  };
1951  const getIdPrefix = (id) => {
1952    if (id.includes('--')) return id.split('--')[0];
1953    const match = id.match(/^(.+?)[-_](\d{5,}|[a-f0-9]{8,})$/i);
1954    return match ? match[1] : null;
1955  };
1956  const getMeaningfulClasses = (el) => {
1957    if (!el.className || typeof el.className !== 'string') return [];
1958    return el.className.trim().split(/\s+/).filter(c =>
1959      c && !c.startsWith('_') && !c.startsWith('js-') &&
1960      c.length < 30 && !/^[a-f0-9]{6,}$/i.test(c) && !/^[A-Z]/.test(c)
1961    );
1962  };
1963  const isUnique = (selector) => document.querySelectorAll(selector).length === 1;
1964
1965  // Returns null if no unique selector can be generated
1966  const generateSelector = (element) => {
1967    if (!element || element === document.body || element === document.documentElement) {
1968      return null;
1969    }
1970    const classes = getMeaningfulClasses(element);
1971
1972    // Priority 1: Clean ID
1973    if (element.id && !hasUid(element.id)) return `#${element.id}`;
1974
1975    // Priority 2: ID with UID → attribute wildcard selector
1976    if (element.id && hasUid(element.id)) {
1977      const prefix = getIdPrefix(element.id);
1978      if (prefix) {
1979        const selector = `[id^="${prefix}-"]`;
1980        if (isUnique(selector)) return selector;
1981      }
1982    }
1983
1984    // Priority 3: Unique class
1985    for (const cls of classes) {
1986      if (isUnique('.' + cls)) return '.' + cls;
1987    }
1988
1989    // Priority 4: Ancestor + target class combinations (walk up to 5 levels)
1990    if (classes.length > 0) {
1991      let ancestor = element.parentElement;
1992      let depth = 0;
1993      while (ancestor && ancestor !== document.body && ancestor !== document.documentElement && depth < 5) {
1994        const ancClasses = getMeaningfulClasses(ancestor);
1995        if (ancClasses.length > 0) {
1996          const s1 = `.${ancClasses[0]} .${classes[0]}`;
1997          if (isUnique(s1)) return s1;
1998          const s2 = `.${ancClasses[0]} > .${classes[0]}`;
1999          if (isUnique(s2)) return s2;
2000        }
2001        if (ancestor.id && !hasUid(ancestor.id)) {
2002          const s3 = `#${ancestor.id} .${classes[0]}`;
2003          if (isUnique(s3)) return s3;
2004        }
2005        ancestor = ancestor.parentElement;
2006        depth++;
2007      }
2008    }
2009
2010    // NO FALLBACK - return null if no unique selector exists
2011    return null;
2012  };
2013  const hasSpecificSelector = (el) => generateSelector(el) !== null;
2014  const shouldSkipElement = (el) => {
2015    if (!el || el.hidden) return true;
2016    if (['SCRIPT', 'STYLE', 'TEMPLATE'].includes(el.tagName)) return true;
2017    if (
2018      el.closest('#pp-nav-panel') ||
2019      el.closest('#pp-nav-pill') ||
2020      el.closest('#pp-pick-overlay')
2021    )
2022      return true;
2023    if (el.hasAttribute('data-pp-message')) return true;
2024    if (!hasSpecificSelector(el)) return true;
2025    return false;
2026  };
2027  const resolveContextName = (providedContextName, messagingTemplate) => {
2028    if (providedContextName && providedContextName !== 'this area') return providedContextName;
2029    const id = messagingTemplate?.id || '';
2030    if (id.includes('cart-drawer')) return 'Cart Drawer';
2031    if (id.includes('cart')) return 'Cart Page';
2032    if (id.includes('product')) return 'Product Page';
2033    return 'this area';
2034  };
2035
2036  // Called when the cart drawer closes (via IntersectionObserver in cartDrawer.liquid)
2037  // and at the start of createNavigationPanel to tear down any existing instance.
2038  // Cleans up pick mode listeners, DOM elements, highlights, and preview clones.
2039  const destroyNavigationPanel = () => {
2040    if (_panelPickModeCleanup) {
2041      _panelPickModeCleanup();
2042      _panelPickModeCleanup = null;
2043    }
2044    document.getElementById('pp-nav-panel')?.remove();
2045    document.getElementById('pp-nav-pill')?.remove();
2046    const preview = document.querySelector('[id$="-preview"][data-pp-message]');
2047    if (preview) preview.remove();
2048    if (_highlightedElement) {
2049      _highlightedElement.style.outline = '';
2050      _highlightedElement.style.outlineOffset = '';
2051      _highlightedElement = null;
2052    }
2053    if (_panelInspectorActivate) {
2054      document.removeEventListener('shopify:inspector:activate', _panelInspectorActivate);
2055      document.removeEventListener('shopify:inspector:deactivate', _panelInspectorDeactivate);
2056      _panelInspectorActivate = _panelInspectorDeactivate = null;
2057    }
2058    document.documentElement.style.cursor = '';
2059  };
2060
2061  const createNavigationPanel = (
2062    initialElement,
2063    messagingTemplate,
2064    warningMessage = null,
2065    contextName = 'this area',
2066  ) => {
2067    let currentTarget = initialElement;
2068    let resolvedContextName = resolveContextName(contextName, messagingTemplate);
2069    destroyNavigationPanel();
2070
2071    const panel = document.createElement('div');
2072    panel.id = 'pp-nav-panel';
2073    const tmpl = document.getElementById('pp-nav-template');
2074    panel.appendChild(tmpl.content.cloneNode(true));
2075
2076    // Create minimized pill button (separate from panel)
2077    const pill = document.createElement('button');
2078    pill.id = 'pp-nav-pill';
2079    pill.innerHTML = 'PayPal Pay Later Messaging';
2080    const applyBtn = panel.querySelector('#pp-apply-btn');
2081    const warningEl = panel.querySelector('#pp-warning');
2082    const step2 = panel.querySelector('#pp-step2');
2083    const step2Dismiss = panel.querySelector('#pp-step2-dismiss');
2084    const contextEl = panel.querySelector('#pp-context-name');
2085    const selectorEl = panel.querySelector('#pp-selector-name');
2086    const updateContextUI = (newContext) => {
2087      resolvedContextName = newContext;
2088      if (contextEl) contextEl.textContent = resolvedContextName;
2089      if (selectorEl) {
2090        selectorEl.textContent = resolvedContextName;
2091      }
2092    };
2093    updateContextUI(resolvedContextName);
2094    const detectContextFromElement = (el) => {
2095      if (el.closest('#CartDrawer, .drawer, .cart-drawer, [id*="cart-drawer"], [class*="cart-drawer"]'))
2096        return 'Cart Drawer';
2097      if (window.location.pathname.endsWith('/cart') || el.closest('.cart, #cart, #main-cart-items, #main-cart-footer'))
2098        return 'Cart Page';
2099      return 'Product Page';
2100    };
2101
2102    // Show warning message if provided
2103    if (warningMessage && warningEl) {
2104      warningEl.innerHTML = `<span class="pp-warning-icon">⚠️</span>${warningMessage}`;
2105      warningEl.style.display = 'block';
2106    }
2107    let isInitialRender = true;
2108    const updateUI = () => {
2109      // Highlight element
2110      highlightElement(currentTarget);
2111      // Update button states
2112      applyBtn.textContent = COPY_BUTTON_LABEL;
2113      applyBtn.classList.remove('applied');
2114      // Reposition messaging — skip on initial render (already placed correctly by auto-detection)
2115      if (!isInitialRender) repositionMessaging();
2116      isInitialRender = false;
2117    };
2118
2119    const highlightElement = (el) => {
2120      if (_highlightedElement) {
2121        _highlightedElement.style.outline = '';
2122        _highlightedElement.style.outlineOffset = '';
2123      }
2124      _highlightedElement = el;
2125      if (el) {
2126        el.style.outline = '2px solid rgba(255,152,0,0.6)';
2127        el.style.outlineOffset = '-1px';
2128      }
2129    };
2130
2131    const repositionMessaging = () => {
2132      if (!currentTarget) return;
2133      const existing = document.getElementById(messagingTemplate.id);
2134      const targetInOverlay = isInOverlay(currentTarget);
2135      const msgInOverlay = existing && isInOverlay(existing);
2136      if (targetInOverlay !== msgInOverlay) {
2137        // Cross-context: reposition messaging in the target's context without touching the original
2138        const allMessaging = document.querySelectorAll('[data-pp-message]');
2139        let contextMsg = null;
2140        for (const el of allMessaging) {
2141          if (isInOverlay(el) === targetInOverlay) { contextMsg = el; break; }
2142        }
2143        if (!contextMsg) {
2144          contextMsg = messagingTemplate.cloneNode(true);
2145          contextMsg.id = messagingTemplate.id + '-preview';
2146        }
2147        contextMsg.remove();
2148        currentTarget.after(contextMsg);
2149        return;
2150      }
2151      if (existing) existing.remove();
2152      const newMessaging = messagingTemplate.cloneNode(true);
2153      currentTarget.after(newMessaging);
2154    };
2155
2156    const collapseBtn = panel.querySelector('#pp-collapse-btn');
2157    const pickBtn = panel.querySelector('#pp-pick-btn');
2158    let pickMode = false;
2159    let pickHoverTarget = null;
2160    let pickOverlay = null;
2161    let pickLabel = null;
2162    let applyBtnResetTimer = null;
2163    let _pickRafId = null;
2164
2165    const enterPickMode = () => {
2166      pickMode = true;
2167      document.documentElement.style.cursor = 'crosshair';
2168      pickBtn.classList.add('active');
2169      pickBtn.innerHTML = '◎ Pick a spot on the page...';
2170      applyBtn.textContent = COPY_BUTTON_LABEL;
2171      applyBtn.classList.remove('applied');
2172      applyBtn.style.display = 'flex';
2173      step2.style.display = 'none';
2174      if (contextEl) contextEl.textContent = resolvedContextName;
2175      // Create overlay for highlighting (pointer-events:none prevents interference)
2176      pickOverlay = document.createElement('div');
2177      pickOverlay.id = 'pp-pick-overlay';
2178      pickOverlay.style.cssText = OVERLAY_STYLE;
2179      pickLabel = document.createElement('div');
2180      pickLabel.style.cssText = OVERLAY_LABEL_STYLE;
2181      pickOverlay.appendChild(pickLabel);
2182      document.body.appendChild(pickOverlay);
2183
2184      document.addEventListener('mousemove', onPickHover, true);
2185      document.addEventListener('click', onPickClick, true);
2186      document.addEventListener('mousedown', onPickSuppressEvent, true);
2187      document.addEventListener('pointerdown', onPickSuppressEvent, true);
2188    };
2189
2190    const exitPickMode = () => {
2191      pickMode = false;
2192      document.documentElement.style.cursor = '';
2193      pickBtn.classList.remove('active');
2194      pickBtn.innerHTML = '◎ Start Picking Placement';
2195      applyBtn.style.display = 'none';
2196      // Remove overlay
2197      const overlay = document.getElementById('pp-pick-overlay');
2198      if (overlay) overlay.remove();
2199      pickOverlay = null;
2200      pickLabel = null;
2201      pickHoverTarget = null;
2202
2203      if (_pickRafId) { cancelAnimationFrame(_pickRafId); _pickRafId = null; }
2204      document.removeEventListener('mousemove', onPickHover, true);
2205      document.removeEventListener('click', onPickClick, true);
2206      document.removeEventListener('mousedown', onPickSuppressEvent, true);
2207      document.removeEventListener('pointerdown', onPickSuppressEvent, true);
2208    };
2209
2210    // Find the nearest visible child element to cursor coordinates
2211    const snapToNearestChild = (parent, cx, cy) => {
2212      const children = parent.children;
2213      if (!children.length) return null;
2214      let best = null;
2215      let bestDist = 30;
2216      for (const child of children) {
2217        if (shouldSkipElement(child)) continue;
2218        const r = child.getBoundingClientRect();
2219        if (r.width === 0 || r.height === 0) continue;
2220        const dx = cx < r.left ? r.left - cx : cx > r.right ? cx - r.right : 0;
2221        const dy = cy < r.top ? r.top - cy : cy > r.bottom ? cy - r.bottom : 0;
2222        const dist = Math.sqrt(dx * dx + dy * dy);
2223        if (dist < bestDist) {
2224          bestDist = dist;
2225          best = child;
2226        }
2227      }
2228      return best;
2229    };
2230
2231    const onPickHover = (e) => {
2232      if (_pickRafId) return;
2233      _pickRafId = requestAnimationFrame(() => {
2234        _pickRafId = null;
2235        let el = document.elementFromPoint(e.clientX, e.clientY);
2236        if (!el || shouldSkipElement(el)) {
2237          document.documentElement.style.cursor = 'not-allowed';
2238          if (pickOverlay) pickOverlay.style.display = 'none';
2239          pickHoverTarget = null;
2240          return;
2241        }
2242
2243        if (el.children.length > 0) {
2244          const snapped = snapToNearestChild(el, e.clientX, e.clientY);
2245          if (snapped) el = snapped;
2246        }
2247
2248        // Skip elements without a unique selector
2249        if (shouldSkipElement(el)) {
2250          document.documentElement.style.cursor = 'not-allowed';
2251          pickHoverTarget = null;
2252          if (pickOverlay) pickOverlay.style.display = 'none';
2253          return;
2254        }
2255        document.documentElement.style.cursor = 'crosshair';
2256        if (el === pickHoverTarget) return;
2257        pickHoverTarget = el;
2258        positionOverlayOnElement(pickOverlay, el);
2259        pickLabel.innerHTML = 'Select this placement';
2260      });
2261    };
2262
2263    const onPickSuppressEvent = (e) => {
2264      if (e.target.closest('#pp-nav-panel')) return;
2265      e.preventDefault();
2266      e.stopPropagation();
2267    };
2268
2269    const onPickClick = (e) => {
2270      if (e.target.closest('#pp-nav-panel')) return;
2271      e.preventDefault();
2272      e.stopPropagation();
2273      e.stopImmediatePropagation();
2274      if (pickHoverTarget && !shouldSkipElement(pickHoverTarget)) {
2275        currentTarget = pickHoverTarget;
2276        updateContextUI(detectContextFromElement(currentTarget));
2277        updateUI();
2278      }
2279    };
2280
2281    // --- Pick button ---
2282    pickBtn.addEventListener('click', () => {
2283      if (pickMode) exitPickMode();
2284      else enterPickMode();
2285    });
2286
2287    _panelPickModeCleanup = () => { if (pickMode) exitPickMode(); };
2288
2289    // --- Minimize / expand ---
2290    collapseBtn.addEventListener('click', () => {
2291      if (pickMode) exitPickMode();
2292      panel.classList.add('minimized');
2293      pill.style.display = 'flex';
2294      highlightElement(null);
2295    });
2296    pill.addEventListener('click', () => {
2297      panel.classList.remove('minimized');
2298      pill.style.display = 'none';
2299      highlightElement(currentTarget);
2300    });
2301
2302    // --- Step 2 dismiss ---
2303    step2Dismiss.addEventListener('click', () => {
2304      step2.style.display = 'none';
2305    });
2306
2307    // Handle copy button click
2308    panel.addEventListener('click', async (e) => {
2309      const button = e.target.closest('#pp-apply-btn');
2310      if (!button) return;
2311      // Skip buttons handled separately
2312      if (button.id === 'pp-collapse-btn' || button.id === 'pp-pick-btn' || button.id === 'pp-step2-dismiss') return;
2313      if (button.id === 'pp-apply-btn') {
2314        const selector = generateSelector(currentTarget);
2315        if (!selector) return;
2316        let copied = false;
2317        try {
2318          // Try multiple copy methods (iframe security blocks clipboard API)
2319          if (navigator.clipboard?.writeText) {
2320            await navigator.clipboard.writeText(selector);
2321            copied = true;
2322          }
2323        } catch {}
2324        if (!copied) {
2325          try {
2326            const ta = document.createElement('textarea');
2327            ta.value = selector;
2328            ta.style.position = 'fixed';
2329            ta.style.opacity = '0';
2330            document.body.appendChild(ta);
2331            ta.select();
2332            copied = document.execCommand('copy');
2333            ta.remove();
2334          } catch {}
2335        }
2336        if (copied) {
2337          applyBtn.textContent = COPIED_BUTTON_LABEL;
2338          applyBtn.classList.add('applied');
2339          if (applyBtnResetTimer) clearTimeout(applyBtnResetTimer);
2340          applyBtnResetTimer = setTimeout(() => {
2341            applyBtn.textContent = COPY_BUTTON_LABEL;
2342            applyBtn.classList.remove('applied');
2343            applyBtnResetTimer = null;
2344          }, 1200);
2345          // Show Step 2 confirmation
2346          step2.style.display = 'block';
2347        }
2348        exitPickMode();
2349      }
2350    });
2351
2352    // --- Inspector mode detection ---
2353    const inspectorWarning = panel.querySelector('#pp-inspector-warning');
2354    let inspectorActive = typeof Shopify !== 'undefined' && Shopify.inspectMode;
2355    const isMac = navigator.platform?.startsWith('Mac') || navigator.userAgentData?.platform === 'macOS';
2356    const shortcut = isMac ? '⌘ ⇧ I' : 'Ctrl + Shift + I';
2357    const enableInspectorMode = () => {
2358      inspectorActive = true;
2359      inspectorWarning.innerHTML = `<span class="pp-warning-icon">⚠️</span> For a better experience, press <strong>${shortcut}</strong> to turn off inspector mode`;
2360      inspectorWarning.style.display = 'block';
2361    };
2362    const disableInspectorMode = () => {
2363      inspectorActive = false;
2364      inspectorWarning.style.display = 'none';
2365    };
2366    _panelInspectorActivate = enableInspectorMode;
2367    _panelInspectorDeactivate = disableInspectorMode;
2368    document.addEventListener('shopify:inspector:activate', enableInspectorMode);
2369    document.addEventListener('shopify:inspector:deactivate', disableInspectorMode);
2370
2371    // Prevent panel/pill clicks from closing cart drawer (themes close drawer on outside mousedown)
2372    const stopBubble = (e) => e.stopPropagation();
2373    panel.addEventListener('mousedown', stopBubble);
2374    panel.addEventListener('pointerdown', stopBubble);
2375    pill.addEventListener('mousedown', stopBubble);
2376    pill.addEventListener('pointerdown', stopBubble);
2377
2378    document.body.appendChild(panel);
2379    document.body.appendChild(pill);
2380    if (inspectorActive) enableInspectorMode();
2381    updateUI();
2382    return panel;
2383  };
2384</script>
2384
2385<!-- END app snippet --><!-- BEGIN app snippet: cartDrawer -->
2385<script>
2386    // Determine correct locator by theme name
2387    const cartDrawerThemeName = window.Shopify.theme.name;
2388    let cartDrawerLocator, cartDrawerNodeToObserve, cartDrawerMutationNode;
2389
2390    switch (cartDrawerThemeName) {
2391      // to support other themes add cases
2392      // default case supports Shopify Free themes
2393      default:
2394        cartDrawerLocator = '.cart-drawer__footer .totals';
2395        cartDrawerNodeToObserve = '#CartDrawer';
2396        cartDrawerMutationNode = 'drawer__inner';
2397        break;
2398    }
2399    // Begin Upstream Messaging Implementation
2400    try {
2401      const cartDrawerMessaging = document.createElement('div');
2402      const price = 0 / 100;
2403
2404      const cartDrawerAttributes = {
2405        'id': 'paypal-upstream-messaging-cart-drawer',
2406        'data-pp-message': '',
2407        'data-pp-placement': 'cart',
2408        'data-pp-style-layout': 'text',
2409        'data-pp-style-text-align': 'right',
2410        'data-pp-style-logo-type': "inline",
2411        'data-pp-style-text-color': "black",
2412        'data-pp-style-text-size': "12",
2413        'data-pp-style-logo-position': "",
2414        'data-pp-amount': price,
2415      };
2416
2417      Object.keys(cartDrawerAttributes).forEach((key) => {
2418        cartDrawerMessaging.setAttribute(key, cartDrawerAttributes[key]);
2419      });
2420
2421      const advancedSettingsEnabled = 'false' === 'true';
2422      const customCartDrawerSelector = ''.trim();
2423
2424      if (advancedSettingsEnabled && customCartDrawerSelector !== '') {
2425        // utils.liquid
2426        cartDrawerLocator = parseSelector(customCartDrawerSelector);
2427      }
2428
2429      if ("enabled" === 'enabled') {
2430        waitForElement(cartDrawerLocator).then(elem => {
2431          elem.after(cartDrawerMessaging.cloneNode());
2432
2433          if (advancedSettingsEnabled && isIsolatedContext() && !document.getElementById('pp-nav-panel')) {
2434            let drawerPanelActive = false;
2435            new IntersectionObserver((entries) => {
2436              if (entries[0].isIntersecting) {
2437                if (!document.getElementById('pp-nav-panel')) {
2438                  setTimeout(() => {
2439                    if (!document.getElementById('pp-nav-panel')) {
2440                      createNavigationPanel(elem, cartDrawerMessaging, null, 'Cart Drawer');
2441                      drawerPanelActive = true;
2442                    }
2443                  }, 300);
2444                }
2445              } else if (drawerPanelActive) {
2446                destroyNavigationPanel();
2447                drawerPanelActive = false;
2448              }
2449            }, { threshold: 0.1 }).observe(elem);
2450          }
2451        });
2452
2453        // Custom selector not found — show navigator with warning when drawer opens
2454        if (advancedSettingsEnabled && customCartDrawerSelector && !document.querySelector(cartDrawerLocator) && isIsolatedContext() && !document.getElementById('pp-nav-panel')) {
2455          const drawerContainer = document.querySelector(cartDrawerNodeToObserve);
2456          if (drawerContainer) {
2457            let warningPanelActive = false;
2458            const warning = 'Selected placement not found on this page. Please choose an element that is present on all page templates.';
2459            recordEvent('appEmbed:advanced-settings-selector-not-found', { locator: cartDrawerLocator });
2460            new IntersectionObserver((entries) => {
2461              if (entries[0].isIntersecting) {
2462                if (!document.getElementById('pp-nav-panel')) {
2463                  setTimeout(() => {
2464                    if (!document.getElementById('pp-nav-panel')) {
2465                      createNavigationPanel(drawerContainer, cartDrawerMessaging, warning, 'Cart Drawer');
2466                      warningPanelActive = true;
2467                    }
2468                  }, 300);
2469                }
2470              } else if (warningPanelActive) {
2471                destroyNavigationPanel();
2472                warningPanelActive = false;
2473              }
2474            }, { threshold: 0.1 }).observe(drawerContainer);
2475          }
2476        }
2477
2478        // utils.liquid
2479        watchForCartChanges(cartDrawerLocator, cartDrawerMessaging);
2480      }
2481    } catch (e) {
2482      // utils.liquid
2483      recordEvent('appEmbed:query-selector-not-found-cart-drawer', { locator: cartDrawerLocator, error: e.message });
2484    }
2485  </script>
2485
2486<!-- END app snippet -->
2487
2488
2489</div><!-- Failed to render app block "4215564508307704909": app block path "shopify://apps/sitemap-noindex-pro-seo/blocks/app-embed/4d815e2c-5af0-46ba-8301-d0f9cf660031" does not exist --><div id="shopify-block-AbmZNMkJoZTRRcUIvb__10830403595879607806" class="shopify-block shopify-app-block"><style>
2490  .rio-withoutBranding .FloatingWidget .R-Logo,
2491  .rio-withoutBranding .CarouselWidget .R-ReviewsioLogo,
2492  .rio-withoutBranding .ElementsWidget .footer__reviewsLogo-container,
2493  .rio-withoutBranding .QnaWidget .footer__reviewsLogo-container,
2494  .rio-withoutBranding .MediaGalleryWidget-prefix .R-ReviewsioLogo,
2495  .rio-withoutBranding .RatingBarWidget .R-PlatformIcon {
2496    display: none !important;
2497  }
2498</style>
2499<script>
2500  window.__REVIEWS_EDITOR__ = false;
2501  window.__REVIEWS_DEMO_CONFIG__ = {
2502    store: 'ecommerce-demo-store',
2503    sku: 'bunch_of_flowers_sku;blue_flowers_sku;white_flowers_sku;pastel_flowers_sku;summer_selection_sku',
2504    widgetIds: {
2505      nuggets: 'W10cpKyjl72VtHv6',
2506      ugc: '7sG9C5qNeKpvhykZ',
2507      floating: 'GBvqmKV1Zy9H4Mpd',
2508      ratingBar: 'pxNMXi7FTlODgr8Q',
2509      survey: 'uLJcD7bFpGMf1Z0C'
2510    },
2511    surveyCampaignId: '392'
2512  };
2513
2514  
2515    var reviewsIoStore = 'balkonkraftwerk-express.de';
2516  
2517
2518  var reviewsIoEnableSyndication = false;
2519
2520  
2521    var reviewsIoLang = 'de';
2522  
2523</script>
2523
2524
2525<script defer src="https://cdn.shopify.com/extensions/01a0f781-40b0-734a-a579-a6ab0f7a7741/reviews-co-uk-product-and-merchant-review-collection-60/assets/reviewsio-preview.js"></script>
2525
2526
2527
2528
2529</div><!-- Failed to render app block "15154131639906026026": app block path "shopify://apps/tinyseo-seo-speed/blocks/broken-link-embed/0605268f-f7c4-4e95-b560-e43df7d59ae4" does not exist --><div id="shopify-block-AQm9TRHFSWXVWZkxWc__15316669992541710076" class="shopify-block shopify-app-block">
2529<script defer src="https://widget.reviews.io/rating-snippet/dist.js"></script>
2529
2530<link rel="stylesheet" href="https://widget.reviews.io/rating-snippet/dist.css" />
2531<script>
2532    (function () {
2533      function initRatingSnippet() {
2534        var hasStore = typeof reviewsIoStore !== 'undefined' && !!reviewsIoStore;
2535        if (!hasStore) return;
2536
2537        if (typeof ratingSnippet !== 'function') return;
2538
2539        // Ensure the target element exists (rating-output block may render after this app embed).
2540        if (!document.querySelector('.ruk_rating_snippet')) return;
2541
2542        var storeOverride = window.__REVIEWSIO_RATING_SNIPPET_STORE_OVERRIDE__;
2543        var storeForSnippet = storeOverride || reviewsIoStore;
2544
2545        ratingSnippet("ruk_rating_snippet",{
2546            store: storeForSnippet,
2547            color: '#ffb701',
2548            
2549              textClr: '#333333',
2550            
2551            linebreak: false,
2552            
2553            
2554              listenForChanges: true,
2555            
2556            
2557            
2558              formatReviewCount: true,
2559            
2560            
2561            lang: (typeof reviewsIoLang !== 'undefined' && reviewsIoLang) ? reviewsIoLang : 'en',
2562            mode: 'default',
2563            showEmptyStars: true,
2564            
2565            enableSyndication: (typeof reviewsIoEnableSyndication !== 'undefined') ? reviewsIoEnableSyndication : false
2566        });
2567
2568        const reviewsIoModal = document.getElementById('reviews_fade');
2569        if (reviewsIoModal) {
2570          reviewsIoModal.classList.add('rio-withoutBranding');
2571        }
2572      }
2573
2574      // Retry to survive slow network/script timing.
2575      var attempts = 0;
2576      var MAX_RATING_SNIPPET_INIT_ATTEMPTS = 20;
2577      var MAX_TIMEOUT_RETRY = 200;
2578      
2579      function tick() {
2580        attempts += 1;
2581        initRatingSnippet();
2582        if (attempts < MAX_RATING_SNIPPET_INIT_ATTEMPTS && (typeof ratingSnippet !== 'function' || !document.querySelector('.ruk_rating_snippet'))) {
2583          window.setTimeout(tick, MAX_TIMEOUT_RETRY);
2584        }
2585      }
2586
2587      // Use window load to maximize chance that the external script executed.
2588      window.addEventListener('load', tick);
2589    })();
2590</script>
2590
2591
2592
2593</div>
2593<script src="https://cdn.shopify.com/storefront/standard-actions.js" type="module" data-source-attribution="shopify.standard_actions"></script>
2593
2594</body>
2595</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.